Netlogo adding to list of lists - list

I am looking to add patch variable values to a list of empty lists. The patches are divided into different zones, and I'm trying to see how certain patch variables differ by zone.
I have an empty list of lists (actually contains 12 lists, but for simplicity):
set mylist [[] [] [] []]
And a list corresponding to the different zones:
set zone-list [1 2 3 4]
Here's how I'm trying to build the lists:
(foreach mylist zone-list [set ?1 lput (sum-zone-variable ?2) ?1])
to-report sum-zone-variable [ n ]
report (sum [patch-variable] of patches with [zone = n])
end
When I run this, mylist stays empty (ie unchanged). I think the problem is with the foreach statement, but I can't figure out what it is. Any help?

I can see the thinking behind foreach mylist [ set ?1 ... ], but NetLogo doesn't work that way. set ?1 ... has no effect on the original list. NetLogo lists are immutable, and ?1 is not a reference to an updatable location in a list — it's just a temporary variable into which a value has been copied. So set ?1 ... is something you will basically never write.
If I understand your question correctly, the relevant primitive here is map. This should do the job:
set mylist (map [lput (sum-zone-variable ?2) ?1] mylist zonelist)

Your basic approach is ok except that you must assign to a name. E.g.,
globals [mylist zone-list n-zones]
patches-own [zone zone-variable]
to setup
set n-zones 4
set zone-list n-values n-zones [?]
ask patches [set zone one-of zone-list]
set mylist n-values n-zones [[]]
end
to go
ask patches [set zone-variable random-float 1]
foreach zone-list [
let total sum [zone-variable] of patches with [zone = ?]
let oldvals item ? mylist
set mylist replace-item ? mylist (lput total oldvals)
]
end
However, you might want to use the table extension for this.

Related

Netlogo: how to assign list values to patches attributes

i am new to Netlogo, so i apologize if this is a trivial question. I would like to assign/copy the values of a list into patches attribute, making sure that the order of the values is respected. The following code does the opposite, that is, it copies the values of a patches attribute (attr1) into list1
patches-own [ attr1 attr2]
to setup
clear-all
ask patches [set attr1 random 10]
let patch-list sort patches
let list1 map [ p -> [attr1] of p ] patch-list
end
now, say that I would like to assign/copy the values of varX into patches attribute attr2, making sure that the order of the values is respected.
let nPix world-width * world-height
let varX (range nPix)
????
any suggestion? thanks
You can let Netlogo iterate through two lists simultanously by feeding the anonymous procedure two inputs. To do that, you need to put brackets around the entire procedure.
patches-own [attr2]
to setup
ca
resize-world 0 4 0 4
end
to go
let nPix world-width * world-height
let varX n-values nPix [random 140]
(foreach sort patches varX [ [the-patch the-var] ->
ask the-patch [set attr2 the-var]
]
)
show varX
ask patches [set pcolor attr2]
end
You can also always opt for a good old while loop where you increment an index (i) within the loop and use that index to couple the corresponding items from both lists.
to go-3
let nPix world-width * world-height
let varX n-values nPix [random 140]
let patch-list sort patches
let i 0
while [i < nPix] [
ask item i patch-list [set attr2 item i varX]
set i i + 1
]
show varX
ask patches [set pcolor attr2]
end

Netlogo code for sorting agents in lists according to their properties

I am trying to sort my agents [industries] into a list and make many further lists based on that initial list sequence.
Each industry has two properties [bid-cap] and [bid-price]. I want first, a sorted list [low-bid-ind] of agents according to their ascending bid-prices, then I want to use the same sequence and fetch the values of [bid-cap] and make a list [low-cap-list], then I want to fetch bid-price for same sequence as [low-bid-ind] list and save it in a list [low-cap-list]. I only make this list so I can make another list with cumulative sum values of the [bid-cap] of agents.
Following is my code. There's an error : LPUT expected input to be a list but got the number 0 instead.
But it doesn't show where the error occurs in the code.
set agentlist-low []
set low-bid-ind []
set low-cap-list []
set sum-low-bid []
set agentlist-low industries with [group = 0]
set low-bid-ind sort-on [bid-price] agentlist-low
foreach low-bid-ind
[ the-industry ->
set low-cap-list lput ([bid-cap] of the-industry) low-cap-list ]
let sum-low 0
let m 0
foreach low-bid-ind
[set m m + 1
set sum-low sum-low + item m low-cap-list
set sum-low-bid lput sum-low sum-low-bid ]
print sum-low-bid
Can anyone help with this problem?
I have looked at Netlogo help and other questions on the internet but I am unable to find an answer.
I cannot reproduce the error you are getting. Are you sure that you are setting low-cap-list and sum-low-bid to empty lists in your actual code? That kind of error normally comes when lput is given a list which has not been initialized, as uninitialized variables in NetLogo are set to 0.
But more generally, NetLogo has a map operation that eliminates the need for looping over lists in most cases. So the loop
foreach low-bid-ind
[ the-industry ->
set low-cap-list lput ([bid-cap] of the-industry) low-cap-list ]
can be written more economically as
set low-cap-list map [the-industry -> [bid-cap] of the-industry] low-bid-ind
and the code segment
let sum-low 0
let m 0
foreach low-bid-ind
[set m m + 1
set sum-low sum-low + item m low-cap-list
set sum-low-bid lput sum-low sum-low-bid ]
can be written as a single line
set sum-low-bid map [m -> sum sublist low-cap-list 0 (m + 1)] range (length low-bid-ind)
map creates a list by performing the operation in brackets on each item in the list it is given. In the latter case, that input list is simply the numbers from 0 to the length of the low-bid-ind list.

Grouping lists by elements in Netlogo

Let us say I have a model in Netlogo and am now interested in developing a reporter/procedure that groups lists according to their first element.
For the sake of example, let's say
globals[list1 list2 list3 listoflists
ordered-list-a
ordered-list-b
]
to setup
set list1 ["a" "b" "c"]
set list2 ["a" "c" "d"]
set list3 ["b" "a" "c"]
set listoflists (list list1 list2 list3)
end
I want to create a list of lists such that in each list you have lists starting with the same element. Hence, the desired output is
[[["a" "b" "c"]["a" "c" "d"]]["b" "a" "c"]]]
i.e, where the first element aggregates all lists with an a in first place, and the second all those starting with a "b".
Ideally, this should be scalable for a large number. I tried
to create-list
set ordered-list-a []
set ordered-list-b []
(foreach listoflists [[i] ->
if item 0 i = "a" [set ordered-list-a lput i ordered-list-a]
if item 0 i = "b" [set ordered-list-b lput i ordered-list-b]
])
end
and then creating a list from a and b, which does the trick, but a) it's incredibly messy, b) requires that I know beforehand the length of the list, which I don't in the real case (it's a turtle procedure) and c) it seems like a lot of unnecessary coding.
Is there some way to extend the procedure above to any number of starting elements (maybe inside a while cycle?) and does not require the creation of a list for each initial list element?
Many thanks
I'm assuming the desired output is supposed to be: [[["a" "b" "c"]["a" "c" "d"]][["b" "a" "c"]]]. I believe you were missing a [ before the second group.
Anyway, a simple, but somewhat inefficient way would be:
; items is a list of items to be grouped
; key is an anonymous reporter that extracts the group label from a single item
to-report group-by [ items key ]
let keys remove-duplicates map key items
report map [ k -> filter [ x -> (runresult key x) = k ] items ] keys
end
Note that the above is a completely generalized grouping function. To use it in your case, you would do:
group-by listoflists [ l -> first l ]
A more efficient way would be to use the table:group-items reporter from the table extension.
table:group-items listoflists [ l -> first l ]

NETLOGO: adding lists of agents' attributes to a list of lists

Hello I am using Netlogo and I am trying to create a list of lists in which every sublist is a couple of agents' attributes. In particular I declare the list as a global variable and I initialize it to an empty list. Then I ask every agent to add a list of their attribute_1 and attribute_2 to the main list. Like this:
globals[mainlist]
set mainlist []
ask agents[
set mainlist sentence [mainlist] [attribute_1 attribute_2 ]
]
This should create a new list composed by the previous mainlist and the list [attribute_1 attribute_2].
Unfortunately this doesn't work and I get the error: EXPECTED LITERAL VALUE referring to "mainlist".
How should I write my code to create my list of lists in the correct way?
Tyr's answer is technically correct, but I would like to suggest a more netlogoish way to do it. Usually, in NetLogo, you don't have to build lists one element at a time. If you find yourself doing that, you might want to stop and try to approach the problem differently.
In this particular case, you can simply take advantage of the of primitive:
[ (list attribute_1 attribute_2) ] of agents
Here is a fully working example:
breed [agents an-agent]
agents-own [attribute_1 attribute_2]
globals [mainlist]
to setup
clear-all
create-agents 10 [
set attribute_1 random 10
set attribute_2 random 10
]
set mainlist [ (list attribute_1 attribute_2) ] of agents
print mainlist
end
You can use lput or fput to add further elements to a list (lput will add the new list item at the end (l=last), whereas fput will add the new item at front (f=first)).
Additionally, you have to use the (list ... ...) primitive instead of [ ] brackets when you want to store variables in a list (brackets only work with constants).
Here is a working example:
globals[mainlist]
to test
ask n-of 20 patches [sprout 1]
set mainlist []
ask turtles
[
set mainlist lput (list xcor ycor) mainlist
]
print mainlist
end

How to implement a numerical formula across the items in a netlogo list

I have to do some operations in netlogo using Lists. While i can do simple tasks with them i am not yet proficient enough to code my current requirements.
I have a scenario where turtles have variables called Current-Age and Previous-Age. And turtles can be born and die if they don't meet a certain threshold.
I want to implement the following formula for each patch.
Best-list = (-1/Previous-Age) * (Distance between Patch & Turtle) for all the turtles
Best = Min [ Best-list]
I know the steps involved but have been unsuccessful in coding them. Following are the steps:
Create a list with all the current turtles that are alive
Create a second list which contains the Previous-Age
Create a third list with the distance between an individual patch and each of the live turtles
Then create another list with the output from the the Best-List formula for all the turtles in the list
Finally find the Min value in the list and store the name/who# of turtle with the minimum value in a separate variable called Best-Turtle
This is the code that i tried but didn't work.
set turtle-list (list turtles)
set turtle-age-list n-values length(turtle-list) [0]
set turtle-patch-dist-list n-values length(turtle-list) [0]
set best-list n-values length(turtle-list) [0]
ask patches[
foreach turtle-list(
set turtle-age-list replace-item ?1 turtle-age-list Previous-Age of turtles with [turtle= ?1]
)
]
I couldn't proceed to the next steps since the above code itself was not correct.
Would appreciate help with the code, thanks in advance.
Regards
First, lists are probably not the simplest way to do this. However, if you must use lists for some reason, I think what you're asking for is possible. I'm not exactly sure what you mean with best- are you trying to have each patch assess which turtle is the best turtle for that patch, and store that variable in a global list? I'm going to assume that's what you mean, but if I'm misunderstanding I think you can adapt what I do here to what you need.
First, any list passed to foreach must be the same length. So, since you mean to do this per-patch, make sure that every patch calls the procedure of list creation, not just for checking the lists. Next, review the dictionary for n-values- the syntax for the reporter means you need to use the reporter you're trying to receive- using n-values length(turtle-list) [0] will just give you a list of zeroes that is the same length as the number of turtles.
So each patch needs to create these lists- make sure you either define the patches-own for the list variables, or just use let to define the lists inside the procedure. You would need a list of ordered turtles, their previous ages, and the distance from the patch calling the procedure to each turtle. Next, you can create a list that generates a value according to your formula. Then, you can use the position primitive to find the location of the minimum value in your formula-generated list and use that to index the turtle with that value.
It might look something like
to numerical
set best-turtle []
ask patches [
let turtle-list (sort turtles) ;;; list of sorted turtles
let turtle-prev-age-list n-values length(turtle-list) [ [i] -> [pre_age] of turtle i ] ;;; list of previous ages of turtles, in same order as above
let turtle-patch-dist n-values length(turtle-list) [ [i] -> distance turtle i ] ;;; list of distance from this patch to each turtle, in same order
set best-list n-values length(turtle-list) [ [i] -> ( ( -1 / ( item i turtle-prev-age-list ) ) * ( item i turtle-patch-dist ) ) ] ;;; list of calculated values for each turtle
let best-position position (min best-list) best-list ;;; gets the index of minimum value
set best-turtle lput item best-position turtle-list best-turtle ;;; adds the best turtle for this patch to the global list of best turtles
]
end
The above procedure assumes that your turtles have a pre_age variable, patches have a best-list variable, and the list of each patches 'best turtle' is held in the global variable best-turtle. From there, you can use foreach to ask turtles in the list to do something. Note that if a turtle's previous age is 0, you will get a divide by zero error.
turtles-own [age previous-age]
to-report evalfrom [_patch]
report (- distance _patch) / previous-age
end
to test
ca
crt 25 [
set age (10 + random 75)
set previous-age age - random 10
]
print min-one-of turtles [evalfrom (patch 0 0)]
end