The use of the special ? variable which takes the values of each of the items in the list as we iterate over the list.
what is the alternative use in the new version of NetLogo software???
The new arrow syntax was introduced with NetLogo 6. Instead of just referring things as ?, this allows you to actually name your variables:
foreach [ 0 1 2 3 ] [ x ->
print x
]
This also allows you to nest these types of blocks and still refer to all the values:
foreach [ 0 1 2 3 ] [ x ->
foreach [ 4 5 6 7 ] [ y ->
print x + y
]
]
Previously, you would have to do this with, for instance, let x ?. With primitives like map and filter, you couldn't do this at all, so it's a big improvement. Note that, if you have more than one variable, you have to wrap the arguments with []:
(foreach [0 1 2 3] [4 5 6 7] [ [x y] ->
print x + y
])
Related
If I have the following: set list [8 1 0 3 4 2 0 1 2 4 25 0 3 3]. I would like to find a way to get, for example, a random item position for zero (2, 6 or 11) or for three (3, 12 or 13).
I have tried with:
let i (position (one-of list = 0) list )
print i
However, that only returns a boolean i. I know I could use position 0 list, but that gives priority to the first position (2, in the case of zero) while I would like it to randomly chosen from all values equal to zero on the list. I thought of using a while[], but I was wondering if there is a faster and simpler way.
In general, when you are working with lists, it is a good idea to familiarise yourself with anonymous procedures and some related primitives like map and filter.
I wrote a quick procedure, called positions that should be able to take care of this. First I create a list containing all the possible indexes: index-list.
Next, I use map to simultaneously go through the input-list and the index-list. It uses ifelse-value to check for each item of the input-list whether or not it corresponds to the input-item that you wanted to check it against. If they correspond, it returns the position of that item in the input-list. Otherwise it returns FALSE.
The final step is to filter out all the FALSE responses so that you are left with a list containing only the positions of your input-item in the input-list.
to-report positions [ input-item input-list ]
let index-list range length input-list
let position-list (map [ [list-item index] -> ifelse-value input-item = list-item [index][FALSE] ] input-list index-list)
report filter [index -> index != FALSE] position-list
end
Testing this gives [2 6 11] as a result, which corresponds with what you would expect
to test
let my-list [8 1 0 3 4 2 0 1 2 4 25 0 3 3]
show positions 0 my-list ;[2 6 11]
end
I am using Netlogo v6.0.4 and I'm getting the following error message when I try to run sample code from an answer I found here on Stack Overflow.
Nothing named ? has been defined
In this answer the following netlogo code is proposed as an answer:
to-report split [ string delim ]
report reduce [
ifelse-value (?2 = delim)
[ lput "" ?1 ]
[ lput word last ?1 ?2 but-last ?1 ]
] fput [""] n-values (length string) [ substring string ? (? + 1) ]
end
The specific ? it does like is the first one in this section substring string ? (? + 1) .
When this answer was written in 2014, Netlogo v5 was in active use and it had a feature called tasks that were lambda methods. But in v6 tasks were replaced by anonymous-procedures.
Is that what the ? are here? How can I fix this error?
You got it in one- the ? in the versions were essentially placeholders for whatever variable was being passed to the task. The 5.3 dictionary entry for foreach has a good example:
foreach [1.1 2.2 2.6] [ show (word ? " -> " round ?) ]
=> 1.1 -> 1
=> 2.2 -> 2
=> 2.6 -> 3
In that case, foreach was taking the input list of [1.1 2.2 2.6] and iterating over it, where the ? takes the place in the command block of the current item being processed. As I understand it, the main syntactical difference in 6.X is that now you explicitly state what that placeholder is, by using the -> operator. So, the exact same idea as above, translated to 6.0 in the foreach example in the 6.0 dictionary entry, looks like this:
foreach [1.1 2.2 2.6] [ x -> show (word x " -> " round x) ]
=> 1.1 -> 1
=> 2.2 -> 2
=> 2.6 -> 3
There, you can see that the x is explicitly being defined as the placeholder. This really improves the clarity of code- you can define the placeholder however you like to be as clear and explicit as you'd like- this (over the top) example works just as well:
foreach [ 1.1 2.2 2.6 ] [ round_me -> show (word round_me " -> " round round_me) ]
If you're using multiple lists, do note that you have to surround the anonymous procedure with ( ) and your placeholder declaration with [ ]- for example:
( foreach [ 1 2 3 ] [ 10 20 30 ] [ [ a b ] -> print a * b ] )
If you're translating your code example, then, you can just focus on explicitly stating the placeholders. It also might help to break it down into the component parts to clarify- more detail in comments:
to-report split2 [ string delim ]
; split the string up into individual characters
let characters fput [""] n-values ( length string ) [ a -> substring string a ( a + 1 ) ]
; build words, cutting where the delimiter occurs
let output reduce [ [ b c ] ->
ifelse-value ( c = delim )
[ lput "" b ]
[ lput word last b c but-last b ]
] characters
report output
end
Now, to follow Nicolas' example from your linked answer, you can call that to-report to split up your text:
to read-example
let line "Example\tof\tsome\ttext"
show split2 line "\t"
end
Gives you:
observer: ["Example" "of" "some" "text"]
Hope that is helpful!
I wish to divide each element in a list by a number, I have tried the following:
Approach 1:
set item 0 (new-vec item 0 vec / number)
set item 1 (new-vec item 1 vec / number)
gives error this isn't something you can use set on
Approach 2:
foreach new-vec
[ set ? ? / number]
doesn't seem to work.
Please help. Thanks in advance.
This is because NetLogo lists are immutable data structures.
If you really want mutability you can always use the array extension, but once you've learned to use NetLogo's immutable lists properly, this is almost never necessary: the lists primitives are usually all that you need.
To divide all the numbers in a list by some other number, use map:
let new-vec [10 50 100]
let number 10
let divided-vec map [ ? / number ] new-vec
will assign the list [1 5 10] to divided-vec.
The map operation builds a new list by applying an operation to each element of the list you pass to it. In the example above, I assigned the new list to a new variable (divided-vec), but if you wanted, you could also assign it back to new-vec:
set new-vec map [ ? / number ] new-vec
This will behave as if you modified new-vec in place, though it won't be the case.
If you want to apply an operation to just one item in a list, you can do it with a combination of replace-item and item:
let my-list [2 4 6 8 10]
show replace-item 1 my-list (item 1 my-list * 100)
will show: [2 400 6 8 10]
This is how to do it in NetLogo 6, which changed anonymous procedures and thus how this is done in map:
let new-vec [10 50 100]
let number 10
let divided-vec map [ i -> i / number ] new-vec
I would like to report a count of the number of common features (e.g. [1 8 4] is three features) an agent (target_turtle) shares with each agent in an agentset (neighbor_turtle). Any suggestions please?
For example: If the agent has the features [1 8 7] and an agent from the agent set has the features [1 7 8], they share one common feature i.e. 1 . The features 8 and 7 are not included as the order of the features is relevant.
The current error I get is: All the list arguments to FOREACH must be the same length.
Cheers,
Marshall
;; reporting overlap between two agents
to-report overlap_between [target_turtle neighbor_turtle]
let suma 0
ask neighbor_turtle
[
(foreach [feature] of target_turtle [Feature] of neighbor_turtle
[ if ?1 = ?2 [ set suma suma + 1] ]
)
report suma
]
end
Your code seems almost correct already, though the ask neighbor_turtle part isn't necessary; you're already using of to switch perspectives.
The error message you're getting seems to indicate that you need to somehow handle the case where the turtle's feature lists aren't the same length.
I'll assume you just want to ignore any trailing items in the longer of the two lists. Here's code that does that:
to-report overlap-between [target-turtle neighbor-turtle]
let features1 [feature] of target-turtle
let features2 [feature] of neighbor-turtle
ifelse length features1 > length features2
[ set features1 sublist features1 0 length features2 ]
[ if length features2 > length features1
[ set features2 sublist features2 0 length features1 ] ]
report sum (map [ifelse-value (?1 = ?2) [1] [0]]
features1 features2)
end
Note that it's idiomatic in NetLogo to name variables like-this not like_this.
I have a nested list, in which each sublist is structured as follows: [[xcor ycor] weight].
Each tick I'd like to update the weight in a sample of these sublists.
I produce the sample (e.g. of size 2) from the nested list total using the Rnd extension (and very helpful answers/comments):
set total [ [[0 1] 1] [[2 3] 2] [[4 5] 3] [[6 7] 4] [[0 1] 1] ]
set sample rnd:weighted-n-of 2 total [ last ? ]
Then I update the weights in the sample (let's say multiplying them by 2) and map them to their respective [xcor ycor]-pair.
let newWeights (map [last ? * 2] sample)
let updatedSample (map list (map [first ?] sample) newWeights)
How can I then replace those entries in total, bearing in mind that it may hold duplicate entries?
This seems to be the perfect job for replace-item, but I don't know how to construct an appropriate index and then pass the respective value from updatedSample.
This is a great problem. The data structure you're using is known as an association list, or alist for short, where the keys are [xcor ycor] and the values are weights. Given your task, it's better to use the keys to look things up rather than indices. Thus, replace-item doesn't really help here. Instead, we can run map on total, using the values from updatedSample if they're there, and defaulting to the values in total. First, we need a convenience function to look things up in the alists. In lisp (a language which influenced NetLogo), this is called assoc. Here it is:
to-report assoc [ key alist ]
foreach alist [ if key = (first ?) [ report ? ] ]
report false
end
Notice that false is returned if alist doesn't contain the key. We want to use the entry returned by this function if it's not false, otherwise use something else. Thus, we need another helper function:
to-report value-or-else [ value default ]
report ifelse-value (value = false) [ default ] [ value ]
end
Finally, we can write a function that does the mapping:
to-report update-alist [ alist updated-entries ]
report map [ value-or-else (assoc first ? updated-entries) ? ] alist
end
Here's it in action:
observer> show update-alist [[[0 1] 1] [[2 3] 2] [[4 5] 3] [[6 7] 4] [[0 1] 1]] [[[0 1] 10] [[4 5] 45]]
observer: [[[0 1] 10] [[2 3] 2] [[4 5] 45] [[6 7] 4] [[0 1] 10]]
You would want to call it like update-alist total updatedSample.