lomper
lomper

Reputation: 379

NetLogo: pair lists containing similar elements

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 1or 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 0in that position. Turtle 4 should create a link with Turtle 2 only (1 in the second and third positions), as should Turtle 3 (1in 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, reduceand filterbut I can't quite get the syntax right...

Happy end of year to everyone

Upvotes: 2

Views: 176

Answers (2)

Seth Tisue
Seth Tisue

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

JenB
JenB

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

Related Questions