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 mean
command 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