Changing filtered values in a nested list - nested-lists

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.

Related

How to access individual values ​of a list item in NetLogo 6.2?

I'm not able to assign the first item value of a list to a turtle variable. For example? I have list3 that has 1 item, that is:
list3: [[5 2]]
I would like the first value of list 3 item 0 to be assigned to reproduction (ie 5) and the second value of list 3 item 0 to be assigned to metabolism (ie 2).
How can I do this?
Thanks in advance
globals [ ValidHabsItem ValidHabs ItemList3 ]
turtles-own [ profiles-habitat metabolism reproduction ]
to setup
let list1 ( list 2 )
let list2 ( list 5 )
let list3 ( reduce sentence ( map [ i -> map [ j -> list j i ] list2 ] list1 ) )
print ( word "list3: " list3 )
let n0 count turtles
let s length list3 * 10
while [ n0 < s ]
[
let c count patches
if c = 0 [ stop ]
ask one-of patches
[
sprout 1
[
set profiles-habitat item ValidHabsItem ValidHabs
set reproduction item ItemList3 list3 ;; list3: [[5 2]];; value 5
set metabolism item ItemList3 list3 ;; list3: [[5 2]];; value 2
]
]
]
set n0 count turtles
end
You can easily understand how to do this by playing in the Command Center and seeing how NetLogo responds to your calls to the list.
Just create a global variable in the Code tab, as globals [my-list], and then follow my statements in the Command Center:
observer> set my-list [[1 2 3] [4 5 6] [7 8 9]]
observer> print my-list
[[1 2 3] [4 5 6] [7 8 9]]
So here we just created a list whose items are other lists.
Therefore, we have:
observer> print first my-list
[1 2 3]
observer> print last my-list
[7 8 9]
observer> print item 1 my-list
[4 5 6]
This means that now, for NetLogo, the whole first my-list statement is equal to [1 2 3]; in other words, it is a list containing those numbers. So you can treat first my-list as any other list. For example, if you want to extract the second item from that list, you will simply do:
observer> print item 1 (first my-list)
2
The parentheses there are optional: they are useful to make the statement more readable to humans, reminding us that the whole first my-list is a list from which we are extracting the second item (i.e. the item with index 1). However, NetLogo does not really need that:
observer> print item 1 first my-list
2
Now you should be able to easily solve your problem, because your case is easier than this: your list3, which in your example is [[5 2]], only has one item in it. This means that first list3 is equal to last list3 which is equal to item 0 list3, all of them being [5 2].
So there you can do:
set reproduction first (first list3)
set metabolism last (first list3)
In general, you can apply this mechanisms to how many levels of nesting you wish.
For example:
observer> set my-list [[[1 2] [3 4]] [[5 6] [7 8]]]
observer> print my-list
[[[1 2] [3 4]] [[5 6] [7 8]]]
observer> print first my-list
[[1 2] [3 4]]
observer> print last (first my-list)
[3 4]
observer> print first (last (first my-list))
3
PS:
Note that, in your while loop, you need to include set n0 count turtles within the command block (as in while [condition] [commands]).
The way you have it now, set n0 count turtles is outside the command block of the loop and this means that the loop will go on forever, because it will never get to the point where n0 is updated and so n0 < s will always evaluate as true.
Also, note that saying
let c count patches
if c = 0 [ stop ]
makes no sense in NetLogo: every model will always have at least one patch, so you will never get to the point of having no patches.
Maybe you wanted to say something like if (count patches with [not any? turtles-here] = 0) [stop]? Just guessing, but here we are going off-topic

Netlogo, Mapping one to one over two lists

I want to find out how to map one to one from two lists. Where length of both the lists are the same.
For Example,
list A = [turtle-0 turtle-3 turtle-5]
list B = [Node-27 node-21 node-29]
I want to map,
turtle-0 to node-27
turtle-3 to node-21
turtle-5 to node-29
and store each of the nodes in turtle-own variable called travel-to.
I have feeling you can achieve this the map or foreach functions, but unfortunately I haven't been successful. Any ideas, Thanks
Using indices, as in geruter's answer, will work, but isn't necessary.
Both map and foreach let you process multiple lists by surrounding the whole call in parentheses, so for example:
observer> show (map [[?a ?b] -> word ?a ?b] [1 2 3] ["a" "b" "c"])
observer: ["1a" "2b" "3c"]
or, shorthand syntax,
observer> show (map word [1 2 3] ["a" "b" "c"])
observer: ["1a" "2b" "3c"]
re:
I have feeling you can achieve this the map or foreach functions, but unfortunately I haven't been successful.
It would help us help you if you showed us your best attempt, and described where you got stuck (was there an error message? incorrect behavior?).
Maybe the pros here will come up with a better solution, but the code below should work.
Actually you could use foreach or map, both return the same results.
The 2 report functions below work for lists, not quiet sure of the also will work with agentsets.
to test
let list1 [1 2 3 4 5 6]
let list2 ["a" "b" "c" "d" "e" "f"]
show foreach-2-lists list1 list2
show map-2-lists list1 list2
end
to-report foreach-2-lists [list1 list2]
let result []
if length list1 != length list2 [ report "Error" ]
let index range length list1
foreach index [ i ->
set result lput ( list ( item i list1 ) ( item i list2 ) ) result
]
report result
end
to-report map-2-lists [list1 list2]
if length list1 != length list2 [ report "Error" ]
let index range length list1
let result map [ i -> ( list ( item i list1 ) ( item i list2 ) ) ] index
report result
end
test will return you the result of both functions:
observer> test
observer: [[1 "a"] [2 "b"] [3 "c"] [4 "d"] [5 "e"] [6 "f"]]
observer: [[1 "a"] [2 "b"] [3 "c"] [4 "d"] [5 "e"] [6 "f"]]
See below for a version using foreach. The trick is to access the two lists through parallel iteration. This won't work with map because you are wanting to do a command (that is, change things) rather than a reporter (extract information).
turtles-own [ my-destination ]
to testme
clear-all
; set up test data lists
create-turtles 5
let agents shuffle sort-on [who] n-of 3 turtles
print agents
let destinations (list "A" (one-of patches) 33 )
print destinations
; do the matching with foreach
let indices range length agents
foreach indices
[ idx ->
ask item idx agents
[ set my-destination item idx destinations
]
]
ask turtles [ show my-destination ]
end

limitation of forming subset in netlogo

Dear Netlogo community,
Last week I posted the question on the same forum about forming subset from a set in netlogo. Here is the link.
How to form subset form a set of numbers in Netlogo
The problem with the above thread is that it wont give the subsets if the set contains more than 21 elements. It throws java heap space out of memory exception. I believe this is because the above thread stored all subsets in one list and eventually list of list reached to its maximum range and throws java heap space out of memory exception. Any help in this regard will be valuable.
A set with N elements has 2^N subsets. Computationally, you cannot do anything with all of them once N is big, but you can still pick from them randomly. Let's assume your N elements are in a list. Then you can pick a random subset:
to-report random-subset [#lst]
let _result []
foreach #lst [
if (one-of [true false]) [
set _result lput ? _result
]
]
report _result
end
Note that this is equivalent to picking a random number in [0..(2^N-1)] and then selection the subset "corresponding" to that number.
If you prefer a more functional approach, you can use
to-report random-subset02 [#lst]
report filter (task [one-of [true false]]) #lst
end
Here is code that runs a task on every subset as soon as that subset is generated, without accumulating all of the subsets in memory:
to foreach-subset [xs fn]
foreach-subset-helper [] xs fn
end
to foreach-subset-helper [prefix xs fn]
ifelse empty? xs
[ (run fn prefix) ]
[ foreach-subset-helper prefix butfirst xs fn
foreach-subset-helper lput (first xs) prefix butfirst xs fn ]
end
Sample run:
observer> foreach-subset [1 2 3] task print
[]
[3]
[2]
[2 3]
[1]
[1 3]
[1 2]
[1 2 3]
Tasks in NetLogo are documented at http://ccl.northwestern.edu/netlogo/docs/programming.html#tasks.

Calculate the number of common features an agent shares with an agentset

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.

NetLogo : How to do multiple operations on lists (find, get , replace, remove , search elements within lists , ....)

I am new to NetLogo and I was wondering if there is a complete reference to do operations on lists, I have read most of the posts here in addition to Netlogo dictionary but for example if I need a list of pairs of numbers like
[[1 2] [2 2] [2 3] ,,, ]
when I search
member? 3 thislist
Will I have the option to say which element of inner list I am considering for the search ? for instance I will get false if it search first element and true if I search second element.
Can anybody please clarify the use of lists in Netlogo?
map, filter, reduce, foreach, n-values, and sort-by provide customizable operations on lists, using tasks. See http://ccl.northwestern.edu/netlogo/docs/programming.html#tasks.
Here's your example using map:
observer> show member? 3 map first [[1 2] [2 2] [2 3]]
observer: false
observer> show member? 3 map last [[1 2] [2 2] [2 3]]
observer: true
It appears Seth answered your initial question. To answer your follow up question on changing an item, you can use replace-item See: http://ccl.northwestern.edu/netlogo/docs/dictionary.html#listsgroup
or use map. Below is an example replacing the first item with a -99 if the second item is 3:
let aList [[1 2] [2 2] [2 3] [4 4] [5 3]]
set aList map [(list ifelse-value (item 1 ? = 3) [-99][item 0 ?] item 1 ?)] aList