How can i get the freq of consecutive numbers in a list in Netlogo?
For example, if my list is:
list = [1 1 1 0 0 1 1 0 1 1 0 0 0 ]
Then the output should look as follows:
output = [3 2 2 1 2 3]
I have decided that this is a job for recursion:
to-report count-consecutive-items [ xs ]
report count-consecutive-items-loop [] nobody xs
end
to-report count-consecutive-items-loop [ counts-so-far last-item remaining-items ]
report ifelse-value (empty? remaining-items) [
; no more items to count, return the counts as they are
counts-so-far
] [
(count-consecutive-items-loop
(ifelse-value (first remaining-items = last-item) [
; this is the same item as the last,
ifelse-value (empty? counts-so-far) [
; if our list of counts is empty, start a new one
[1]
] [
; add one to the current count and keep going
replace-item (length counts-so-far - 1) counts-so-far (1 + last counts-so-far)
]
] [
; this is an item we haven't seen before: start a new count
lput 1 counts-so-far
])
(first remaining-items)
(but-first remaining-items)
)
]
end
to test
let result count-consecutive-items [1 1 1 0 0 1 1 0 1 1 0 0 0]
print result
print result = [3 2 2 1 2 3]
end
I'm sure that someone else can come up with a nice imperative version that will be much easier to understand than this, but you can consider this as a pedagogical exercise: if you manage to understand this code, it will help you on your way to NetLogo enlightenment.
to-report countRuns [#lst]
if 0 = length #lst [report #lst]
let val first #lst
let _ct 1
let cts []
foreach butfirst #lst [? ->
ifelse ? = val [
set _ct (1 + _ct)
][
set cts lput _ct cts
set val ?
set _ct 1
]
]
report lput _ct cts
end
Related
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
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
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]]
I have a list with 20 items and I want to count the number of occurrences of each item in list. I know code below
to-report frequency [i lst]
report length filter [? = i] list
end
but I do not want to write 20 lines like
let C1 frequency 1 (list1)
let C2 frequency 2 (list1)
.
.
.
let C20 frequency 20 (list1)
That's:
map [frequency ? list1] n-values 20 [? + 1]
Sample run:
observer> set list1 [1 4 4 7 10 10 10 14]
observer> show map [frequency ? list1] n-values 20 [? + 1]
observer: [1 0 0 2 0 0 1 0 0 3 0 0 0 1 0 0 0 0 0 0]
For NetLogo 6, OP's function would be this:
to-report frequency [an-item a-list]
report length (filter [ i -> i = an-item] a-list)
end
Making a frequency list is revised like this:
map [ i -> frequency i list1] (n-values 20 [i -> i])
How can I have file contents separated by spaces read into NetLogo as a list?
For example, with a file containing data such as these:
2321 23233 2
2321 3223 2
2321 313 1
213 321 1
I would like to create lists such as these:
a[2321,2321,2321,213]
b[23233,3223,313,321]
c[2,2,1,1]
Well, here is a naive way to do it:
let a []
let b []
let c []
file-open "data.txt"
while [ not file-at-end? ] [
set a lput file-read a
set b lput file-read b
set c lput file-read c
]
file-close
It assumes the number of items in your file is a multiple of 3. You will run into trouble if it isn't.
Edit:
...and here is a much longer, but also more general and robust way to do it:
to-report read-file-into-list [ filename ]
file-open filename
let xs []
while [ not file-at-end? ] [
set xs lput file-read xs
]
file-close
report xs
end
to-report split-into-n-lists [ n xs ]
let lists n-values n [[]]
while [not empty? xs] [
let items []
repeat n [
if not empty? xs [
set items lput (first xs) items
set xs but-first xs
]
]
foreach (n-values length items [ ? ]) [
set lists replace-item ? lists (lput (item ? items) (item ? lists))
]
]
report lists
end
to setup
let lists split-into-n-lists 3 read-file-into-list "data.txt"
let a item 0 lists
let b item 1 lists
let c item 2 lists
end