Reputation: 379
I wonder if anyone can help with this question for which I am a bit lost. I have turtles with three-dimensional boolean lists [a b c]
where a, b, c in {0, 1}
. I would like each turtle to create a link with another one who has 1
on all the same positions of the list. A turtle should thus identify where in its list it has 1
and look for another turtle that has 1
in the every same position. Where the original turtle has 0
, the second one can have either 1
or 0
.
That is:
Turtle 1 [0 1 0]
Turtle 2 [1 1 1]
Turtle 3 [1 0 1]
Turtle 4 [0 1 1]
Turtle 1 should create links with Turtle 2 or Turtle 4 (because both have 1
on item 1
, the second position) but not with Turtle 3 since it has a 0
in that position. Turtle 4 should create a link with Turtle 2 only (1
in the second and third positions), as should Turtle 3 (1
in the first and third position), and Turtle 2 should be unable to create links (no turtles with 1
in all three positions).
What I have is
let candidate one-of turtles with [list1 = [list1] of myself]
create-link-with candidate
Which of course doesn't work since the turtle will look for another one that has exactly the same list (including zeros) and not one that has the same positions for 1
only. I know this should be related to foreach
, map
, reduce
and filter
but I can't quite get the syntax right...
Happy end of year to everyone
Upvotes: 2
Views: 176
Reputation: 30453
Here's a recursive solution:
to-report match-ones [source target]
if empty? source [ report true ]
if first source = 1 and first target != 1 [ report false]
report match-ones butfirst source butfirst target
end
and a version that uses foreach
without using indexing:
to-report match-ones [source target]
(foreach source target [[?s ?t] ->
if ?s = 1 and ?t != 1 [ report false ]
])
report true
end
I think this last version is probably clearest, but it's a matter of personal preference.
Upvotes: 1
Reputation: 17678
I'm sure someone who is better at lists will be able to do this with reduce
or other clever tools. However, since position
only gives the first position, I can't see any vectorised way to do this. So I have iterated with foreach
instead.
to testme
let list1 [0 1 0]
let list2 [1 1 1]
let list3 [1 0 1]
let list4 [0 1 1]
type "check 1, 2: " print match-ones list1 list2
type "check 1, 3: " print match-ones list1 list3
type "check 1, 4: " print match-ones list1 list4
type "check 2, 1: " print match-ones list2 list1
type "check 2, 3: " print match-ones list2 list3
type "check 2, 4: " print match-ones list2 list4
type "check 3, 1: " print match-ones list3 list1
type "check 3, 2: " print match-ones list3 list2
type "check 3, 4: " print match-ones list3 list4
type "check 4, 1: " print match-ones list4 list1
type "check 4, 2: " print match-ones list4 list2
type "check 4, 3: " print match-ones list4 list3
end
to-report match-ones [#source #target]
foreach range length #source
[ x -> if item x #source = 1 and item x #target != 1
[ report false
]
]
report true
end
The reporting procedure takes the first list and simply runs through checking each item. If it's a 1 and the other list doesn't have a 1 then the procedure reports false
(and ends without testing the others). If that never happens, the the procedure reports true
.
The testme procedure is simply there to call the procedure and check your test data. The code is a complete model.
Upvotes: 2