When I setup my model, I also upload a csv file containing multiples columns, after some research, I found that it is read as a list of lists (each line being a list).
set yield-data sentence yield-data (list (list file-read file-read file-read file-read file-read))
When I run the model (land use model), for each patch, a value from the list of lists (yield-data
from above) must be used in a simple arithmetic that will define its next land use category.
I'm not there yet, I first aim to figure out how to look-up for values inside the my-list
See below the reproducible code, with my-list
instead of yield-data
, except for the procedure to test
for which I struggling. I'm still new to object-oriented modeling...
globals [
my-list
my-rd-list
]
patches-own [
year
varA
varB
temp-varC
]
to setup
;; here I just create patches with different values that also appear in the list
ca
resize-world 9 * 0 ( 9 * 1 ) ( 9 * -1 ) 9 * 0
set my-list [[2015 3 2 8] [2016 5 1 10] [2017 7 0 12]]
ask patches with [pxcor < 3] [set year 2015]
ask patches with [pxcor > 3] [ set year 2016]
ask patches with [pxcor > 6] [ set year 2017]
ask patches with [pycor > -3] [ set varA 3]
ask patches with [pycor < -3] [ set varA 5]
ask patches with [pycor < -6] [set varA 7]
ask patches [set varB random 3]
end
to test
;; need to add a "while n <= number of list inside the list"
let n 1
foreach item n my-list [
x ->
ask patches with [year = item 0 item n my-list and varA = item 1 item n my-list and varB = item 2 item n my-list] [set pcolor orange set temp-varC item 3 item n my-list]
set n n 1
]
end
The idea is that for each list (for example [2015 3 2 8], the last value of the list is used to do the little math afterwards for the patch that patches the criteria of having year = 2015, varA= 3 and varB=2, I though it would be easier to store it in the patch as a temporary variable. The code is now working thanks to understanding better how list work. However,
1) I'm however missing how to count how many list there are in the main list - or how many lines there are in the original txt file I mentionned in the beginning.
2) I'd like varA to be inside, let's say, -1 / 1 around the value of item 1 item n my-list
, something like here-below that does not work
ask patches with [year = item 0 item n my-list and varA < item 1 1 (item n my-list) and varA > item 1 - 1 (item n my-list) and varB = item 2 item n my-list] [set pcolor orange set temp-varC item 3 item n my-list]
Then I have a "fundamental" question : when one patch will be checked, his temp-varC
updated and varA
updated too based on the values in my-list
: can it still be elligble in that loop for a next update of temp-varC
? Because varA will change so the combination of "items" will change and it can have an updated temp-varC
(but I don't want that!).
CodePudding user response:
On how to count how many lists are in my-list
Each inner list is just an item of my-lists
, so length my-lists
will tell you how many inner lists are there.
On the interval around varA
This only requires you to devise an arithmetical condition that mirrors what you want. I guess it can be done in at least a couple of ways.
For example, for the condition in which you want to apply this interval, instead of having something like:
varA = item 1 some-list
you could have have:
abs (varA - item 1 some-list) <= 1
Approach using while
Let me first give you a solution using while
, because it is the way you approached the issue and because it is useful to clarify how to treat lists in this context.
After that, a more concise approach using filter
.
With the while
approach you don't need foreach
, because foreach
runs a command for every item of a list. In your example, where you use foreach
, you are telling your anonymous procedure to store as x
each item of my-list
(i.e. each inner list) one at a time, and to run some commands for each x
. However, you never address x
in such commands, which proves that foreach
is superflous.
This means that, using the two pieces of information above about the length of a list and the interval in the condition, you can achieve your goal by just doing:
to test
ask patches [
let i 0
while [i < length my-list] [
let current-inner-list item i my-list
ifelse ((year = item 0 current-inner-list) AND (abs (varA - item 1 current-inner-list) <= 1) AND (varB = item 2 current-inner-list))
[set temp-varC item 3 current-inner-list
stop]
[set i i 1]
]
]
end
This way, the loop will check inner lists until it finds the correct one, then sets temp-varC
and then executes stop
so that the loop ends without having to iterate through all of my-list
.
Note that parentheses around individual booleans are optional, I use them for readability.
Approach using filter
A more concise approach uses filter
: this primitive takes a reporter and a list as arguments, and returns (reports, in NetLogo jargoon) a list containing only the items from the original list for which the reporter evaluates as TRUE
.
In your case, this means that you can do:
to test
ask patches [
set temp-varC last (first (filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list))
]
end
Let's break this code down.
The filter
command is being passed an anonymous reporter (the usual concatenation of conditions) and my-list
, so it will report only the items of my-list
for which all of those conditions evaluate as TRUE
.
For example: for a patch that has year = 2017
, varA = 7
and varB = 0
, the filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list
statement will report [[2017 7 0 12]]
, which is my-list
but containing only that one item.
Given that you are only interested in extracting 12, you need two more steps:
- Extracting the only inner list by using
first
orlast
oritem 0
. Thereforefirst (filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list)
reports[2017 7 0 12]
; - Extracting the last item of this inner list by using
last
oritem 3
. Thereforelast (first (filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list))
reports12
.
This is why doing set temp-varC <all of the above>
does the job.
A note: this code with filter
does not currently work with your example, because my-list
does not currently contain enough combinations of values to cover all patches. This means that, for some patches, filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list
will report an empty list []
, and therefore running first (filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list)
will give you an error. If, in the real model, my-list
will contain any possible combination of year
, varA
and varB
that a patch can have, then there is no problem. Otherwise, you would probably need to anticipate that possibility and use ifelse
, or ifelse-value
, to assign a default value to temp-varC
in case no matching list is found inside my-list
. Something like:
to test
ask patches [
let my-list-filtered filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list
set temp-varC ifelse-value (empty? my-list-filtered) [0.5] [last first my-list-filtered]
]
end
Regarding multiple updates of temp-varC
No: the way ask
works in NetLogo is that it first gathers all agents belonging to the agentset being summoned, and then each of them is asked to perform the actions in the command block. That's it, no dynamic update of agentsets.
This code verifies it:
to test-ask-command
clear-all
create-turtles 2 [
set color 25
]
ask turtles with [color = 25] [
show "Hi!"
ask other turtles [
set color 35
]
]
end
This shows the following in the Command Center:
observer> test-ask-command
(turtle 1): "Hi!"
(turtle 0): "Hi!"
which means that the second turtle said hi even if, by the time it got to perform its action, its color had already been changed to 35.
Side notes
- Is it intentional that you are leaving some patches with
year = 0
and withvarA = 0
? Because, in yoursetup
, you are only using strictly-greater and strictly-less symbols - so that all patches withpxcor = 3
don't get to setyear
and all patches withpyxcor = -6
don't get to setvarA
. - To be precise with style, I suggest choosing variable names that are significant without the need of capital letters: if you inspect any patch, you will see that for example
varA
is justvara
for NetLogo.