Iterate over a list of distances in Netlogo - list

I need help for the following issue.
Basically, I have four turtles and a list of distances among them, let's say [ 0 1 2 3 ]. Zero is the distance of a turtle from itself.
I want to obtein the following list [ 0, 1/5, 2/4, 3/3 ]. In other terms, I want to divide each number to the sum of all the other numbers. Can you help me?

The map primitive allows you to make a calculation for each item in a list separately and returns a new list of the results, as shown by the following examples from the Netlogo dictionary:
show map round [1.1 2.2 2.7]
=> [1 2 3]
show map [ i -> i * i ] [1 2 3]
=> [1 4 9]
Now applying this to your case, I let every item of the list be divided by the sum of all items in the list minus its own value:
to test
let the-list [ 0 1 2 3 ]
let total sum the-list
let new-list map [ x -> x / (total - x)] the-list
show new-list
;=> [0 0.2 0.5 1]
end

Related

How to use a command all the 4th item nested lists in netlogo

I have built a long nested list having the following profile:
set my-list [A 1 2 3 4] [B 5 6 7 8] [C 9 10 11 12]
I'd like to apply the meancommand to the fourth item of each nested lists, so in the example to
4 8 12
but without building a list in loop that would look like [4 8 12] (to save computing time).
Is it possible ?
using let comp mean (item i item 4 (my-list)) or let comp mean (item 4 (my-list)) aren't obviously working.
The answer would be useful to other part of the model that I'm building.
Thanks for your time.
The map primitive is very well suited for these sorts of calculations with lists. It allows you to perform a reporter separately for each part of a list and then returns the results as a new list.
let test-list [1 2 3]
show map [x -> x + 1] test-list
;> [2 3 4]
In your case, you would use map to cycle through your list of lists, and use the item primitive to extract the necessary number from each sublist (map [x -> item 4 x ] my-list). This then returns them as a list of which you can take the mean.
to check-mean-2
let my-list [["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
let my-mean mean map [x -> item 4 x ] my-list
print my-mean
end
EDIT: Although mine looks more efficient on first glance, Matteo's version actually runs quicker (at least on my machine)
globals [my-list]
to setup
set my-list [["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
end
to check-mean
let timer-list []
repeat 10 [
reset-timer
repeat 1000000 [
let the-sum 0
let i 0
while [i < length my-list] [
set the-sum (the-sum + item 4 (item i my-list))
set i i + 1
]
let my-mean the-sum / i
]
let the-timer timer ; ~0.207
show the-timer
set timer-list lput the-timer timer-list
]
show word "mean: " (mean timer-list) ; 0.210
end
to check-mean-2
let timer-list []
repeat 10 [
reset-timer
repeat 1000000 [
let my-mean mean map [x -> item 4 x ] my-list
]
let the-timer timer
show the-timer
set timer-list lput the-timer timer-list
]
show word "mean: " (mean timer-list) ; 0.235
end
ANOTHER EDIT: Finally two more versions using reduce instead of map. Version 3 is the fastest of them all but you should take notice of the fact that my-list has a 0 added to it in this version. This might make is slightly less conveniet for other purposes. You can also add this 0 to it during the calculation as seen in version 4, but that drives up the time again.
to check-mean-3
set my-list [0 ["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
let timer-list []
repeat 10 [
reset-timer
repeat 1000000 [
let my-sum reduce [ [x y] -> x + item 4 y] my-list
let my-mean my-sum / (length my-list - 1)
]
let the-timer timer
show the-timer
set timer-list lput the-timer timer-list
]
show word "mean: " (mean timer-list) ; 0.170
end
to check-mean-4
set my-list [["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
let timer-list []
repeat 10 [
reset-timer
repeat 1000000 [
let my-new-list fput 0 my-list
let my-sum reduce [ [x y] -> x + item 4 y] my-new-list
let my-mean my-sum / (length my-list - 1)
]
let the-timer timer
show the-timer
set timer-list lput the-timer timer-list
]
show word "mean: " (mean timer-list) ; 0.226
end
First things first: did you mean to say that such nested list is built such as the one below?
set my-list [[A 1 2 3 4] [B 5 6 7 8] [C 9 10 11 12]]
Note the extra pair of square brackets, that make this actually a list of lists. Even if that was the case, NetLogo wouldn't let you use that syntax:
Either because A, B and C are lacking quotation marks if you intend them to be strings;
Or because, if A, B and C are variables, NetLogo expects literal values (we can get around this problem by using (list ...) instead of []).
In the first case, it would have to be:
set my-list [["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
In the second case, it would have to be:
set my-list (list (list a 1 2 3 4) (list b 5 6 7 8) (list c 9 10 11 12))
All of the above just to make sure we are all on the same page (in general, please make sure that the code you post in your question is valid for the language you are asking about. As you can see, it would save a lot of time and space!).
Anyway I imagine that what you come up with is something of this type:
[["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
I would use a while loop to iterate through the inner lists. You can create a local variable to keep track of the sum of the numbers you extract as you iterate through the inner lists, and then divide that sum by the number of times you extracted a number:
to check-mean
let my-list [["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
let the-sum 0
let i 0
while [i < length my-list] [
set the-sum (the-sum + item 4 (item i my-list))
set i i + 1
]
print the-sum / i
end
From the answers above and adding a step in the procedure (mean and sd for groups of items having the same "region" in the list), here-below is my final code using map as the mean and sd are already calculated in a while-loop. Moreover, I assumed that calculating manually the standard deviation would create even more lists of list and complicate the code.
to create-successor-list
set successor-list map [inner-list -> (list inner-list 0 0 ) ] region-data
let i 0
while [i < length region-data] [
let current-item item i region-data
set temp-profitability-list (filter [current-inner-list -> (item 1 current-inner-list = current-item)] profitability-list )
set prof-mean mean map [x -> item 4 x ] temp-profitability-list
set prof-sd standard-deviation map [x -> item 4 x ] temp-profitability-list
set successor-list replace-item i successor-list (replace-item 1 item i successor-list (prof-mean))
set successor-list replace-item i successor-list (replace-item 2 item i successor-list (prof-sd))
set i i + 1
set temp-profitability-list [ ]
]
end

How can I combine two lists in Netlogo without getting extra brackets?

I've been trying to combine two lists, angles and distance, into a new list, and I want to do it in a way where angles' first element is combined with the first x elements in distance, like this:
[[45 0.5] [45 1] [45 2] [135 0.5] [135 1] [135 2] etc.
My problem is that it looks like this:
[[[45 0.5] [45 1] [45 2]] [[135 0.5] [135 1] [135 2]] etc.
In other words, it has brackets around each couple of items that have the same element from angles.
This is how I got here:
let q 0
let temp ""
while [ q < length list1 ]
[
let l item q list1
let t 0
while [t < 9] [
let d item t coarse-distance-list
set temp (word temp "[ " d " " l " ] ")
set t t + 1
]
set q q + 1
]
set chromosomes temp
List1 is angles and list2 is distance. I know I can probably do this in a way more easy and efficient way, but at the moment getting the list right is my first priority of course.
Thanks in advance for any help!
I´m sure the pros here will come up with a smarter solution, but try this:
to test
let list1 (list 45 45 45 135 135 135)
let list2 (list 0.5 1 2 0.5 1 2)
let temp range length list1
let result []
foreach temp [ i ->
set result lput ( list ( item i list1 ) ( item i list2 ) ) result
]
show result
end
This will return you:
observer> test
observer: [[45 0.5] [45 1] [45 2] [135 0.5] [135 1] [135 2]]

Tie breaker in Netlogo sorting process

I want to sort the turtles according to their "var" values. My code is:
globals [liste]
turtles-own [var]
to setup
clear-all
create-turtles 5 [setxy (random 5) (random 5)]
ask turtle 0 [set var 1]
ask turtle 1 [set var 1]
ask turtle 2 [set var 1]
ask turtle 3 [set var 2]
ask turtle 4 [set var 3]
set liste [who] of turtles
set liste sort-by [([var] of turtle ?1) < ([var] of turtle ?2)] liste
show liste
end
This code is working and I obtain the following results during several exceutions
observer: [0 2 1 3 4]
observer: [1 0 2 3 4]
observer: [0 2 1 3 4]
The problem that is I want that the sorting process returns always the same results. From my point of view, it is possible to add a tie breaker, but I don't know how to do it in Netlogo. Any suggestions?
You could create your own custom reporter that considers the tie breaker. Below, I create a turtle-compare reporter which checks if the vars are equal, if so, they compare based on the who (a guaranteed unique identifier as the tie breaker). Otherwise, the turtles are compared by the variable you specified.
I would like to note, you could just pass in the turtles directly, rather than a list of their whos.
to setup
...
show sort-by turtle-compare turtles
...
end
to-report turtle-compare [t1 t2]
report ifelse-value ([var] of t1 = [var] of t2)
[[who] of t1 < [who] of t2]
[[var] of t1 < [var] of t2]
end

NetLogo: excluding items from a list after they have already been chosen

I am using the setxy function to set the area that my turtles will be placed in. I made a list of the x values and y values. But I don't want more than 1 turtle at the same point. I'm not sure how to stop this from happening. This is the code that I am using for this:
create-vcells 20
[ setxy one-of [0 0.6 1.2 1.8 2.4 3]
one-of [0 0.6 1.2 1.8 2.4] ]
Does anyone have any insight? Thanks!
I assume that vcells is a breed. I'll use regular turtle commands, but you'll be able to figure out how to adapt my examples to your code.
You can just use a double loop to look at each possible combination of x and y coordinates, putting the create- command inside the loops:
let xs [1 2 3 4]
let ys [10 15 20 25]
foreach xs [
let x ?
foreach ys [
let y ?
create-turtles 1 [setxy x y]
]
]
foreach loops through the items in a list (xs in the outer foreach, ys in the inner one). Inside a foreach block, ? refers to the current item from the list, and refers to each one in turn. I assigned the value of ? in the outer foreach block to a variable so that I could refer to its value from xs inside the inner foreach block, where ? would refer to one of the elements of ys instead. (Then I assigned the inner ? to a variable as well just for the sake of clarity.)
If instead of every combination of coordinates, you just want to pair the x-coordinates and y-coordinates in order, you can use foreach with multiple lists:
(foreach xs ys [
create-turtles 1 [setxy ?1 ?2]
])
Here ?1 refers to the current element from the first list (xs), and ?2 refers to the current element from the second list (ys). Note that in this case you have to wrap the entire expression in parentheses.
You can generate n unique pairs of coordinates (contained in your two lists) as follows:
to-report n-pairs [#n #lst01 #lst02]
let _n1 length #lst01
let _n2 length #lst02
let _nmax (_n1 * _n2) ;possible pairs
if (#n > _n1 * _n2) [error "#n is too big"]
let _idxs n-of #n n-values _nmax [?]
report map [(list
item int (? / _n2) #lst01
item (? mod _n2) #lst02)
] _idxs
end

How to call a list for update multiple times until a condition is fulfilled in Netlogo

I am new to Netlogo and still learning , what i want to do is call a list after an update is done and do another update to it until a condition is reached , if a have a list
let xy [[-2 6][-1 6][0 6][-1 6][-2 6][1 5][2 5][-3 9][-4 9][-5 9][-6 9][-3 9]]
let same true
I am trying to remove from the list the first sublist between two same elements [-2 6 ][-1 6][0 6][-1 6][-2 6] then i also want to remove the sublist between the other two same elements [-3 9][-4 9][-5 9][-6 9][-3 9] until there are no more elements that repeat in this case result should be [[1 5] [2 5]] and i control this list after removing the sublists with the condition:
if length xy = length remove-duplicates xy [ set same false ]
I have already done the removal code below and it removes the first sublist but i might have a lot of sublists , and i want to know how after one removal can i get again the updated list (in these case i should somehow take the final-list in the code) and control it again with these condition.
I was thinking to do a to-report procedure and a while loop , for example (maybe i am wrong with this)
to-report update-list [list]
while [same != false ]
[ ; do the removal stuff
set list-xy item POSITION (FIRST MODES xy) xy xy
let first-pos POSITION (FIRST MODES xy) xy
set list-temp remove-item first-pos xy
set sec-pos position list-xy list-temp + 1
set sublist-1 sublist xy 0 first-pos
set sublist-2 sublist xy sec-pos length xy
set final-list sentence sublist-1 sublist-2
set xy final-list
; the condition if i don't have any duplicates the size of two lists should have the same size , no duplicates
if length xy = length remove-duplicates xy
[ set same false ]
]
report update-list xy
I am not sure what to report at the end of the procedure and how to recall the list again, so i can remove all those sublists.
Any ideas are appreciated, thank you
This is easiest to solve using recursion:
to-report remove-fenced-sublists [xs]
if empty? xs
[ report [] ]
let pos position first xs butfirst xs
if not is-number? pos
[ report fput first xs remove-fenced-sublists butfirst xs ]
report remove-fenced-sublists sublist xs (pos + 2) length xs
end
Sample run:
observer> show remove-fenced-sublists [[-2 6][-1 6][0 6][-1 6][-2 6][1 5][2 5][-3 9][-4 9][-5 9][-6 9][-3 9]]
observer: [[1 5] [2 5]]
If I understand your goal, your core need can be captured by building up a new list item by item but trimming it whenever a duplicate appears. For a single new item this is:
to-report trim-or-grow [#list #item]
let _i position #item #list
report ifelse-value (_i != false) [sublist #list 0 _i] [lput #item #list]
end
You can then reduce with this reporter:
to test
let xy [[-2 6][-1 6][0 6][-1 6][-2 6][1 5][2 5][-3 9][-4 9][-5 9][-6 9][-3 9]]
print reduce trim-or-grow fput [] xy
end