Reputation: 1399
My patches have cost
and gain
attributes, and I would like to sort a list of patches with the minimum cost
and the maximum gain
. The sort-by
function works for sorting on one attribute but how can I sort on both attributes?
Upvotes: 2
Views: 1159
Reputation: 14972
To sort an agentset on many attributes, you can use either sort-by
or sort-on
:
patches-own [ cost gain ]
to sort-patches
ca
ask patches [
set cost random 100
set gain random 100
]
let patches-sorted-by sort-by [
([ cost ] of ?1 > [ cost ] of ?2) or
([ cost ] of ?1 = [ cost ] of ?2 and [ gain ] of ?1 < [ gain ] of ?2)
] patches
show map [[ list cost gain ] of ? ] patches-sorted-by
let patches-sorted-on sort-on [ (cost * -1000) + gain ] patches
show map [[ list cost gain ] of ? ] patches-sorted-on
end
Which one you prefer is up to you. Using sort-on
requires to carefully construct your formula (i.e., the above would not work if you can have gains greater than 1000) but is slightly less verbose.
Edit: a more general way of sorting on multiple criteria
OK, this is probably overkill for your situation, but I came up with something a lot more general:
to-report sort-by-criteria [ criteria items ]
; `criteria` needs to be a task that returns a list of numbers
report sort-by [
compare-lists (runresult criteria ?1) (runresult criteria ?2)
] items
end
to-report compare-lists [ l1 l2 ]
report ifelse-value (empty? l1 or empty? l2) [ false ] [
ifelse-value (first l1 = first l2)
[ compare-lists but-first l1 but-first l2 ]
[ first l1 < first l2 ]
]
end
What you need to pass sort-by-criteria
is a task
that, given one of the items that you want to sort, will report a list of numbers according to which your items will be sorted.
In your case, you would use it like:
let sorted-patches sort-by-criteria (
task [[ list (-1 * cost) gain ] of ? ]
) patches
For two criteria, it's probably not worth using, but if you had a long list of criteria, it would probably be a lot easier and clearer to use than any of the other methods.
Upvotes: 3