Search code examples
listnetlogoagent-based-modeling

Extracting values from lists in Netlogo


I have a model where patches have the value of "habitat" and I have a csv file of animal selection ratios. The goal is that I want each agent to survey the habitats within their next step to decide where to move.

The code is as follows.

to move_females_test
  let this_step (one-of step_length_lsf / patch-length)
  let available [habitat] of patches in-radius this_step
  let unique-habitats remove-duplicates available
  print available
  print unique-habitats

  ifelse length unique-habitats = 1 [
    ; If there is only one unique habitat, move as per the existing code
    set heading (one-of turning_angles_lsf * 100)
    fd this_step
  ] []
  
end 

so for each tick the turtle generates something like this

[Pastures Pastures Pastures Pastures Pastures]

in which case there is no need to decide - so they move randomly. Or something like this

[Pastures Pastures Pastures Scrub Arable]

In which case I want them to draw from a list called selection I have initalised and populated with values from a habitat selection model. The list looks like this, as an example.

[[Pastures 1] [Pastures 1] [Arable 2.485988192] [Scrub 0.684336963] [Arable 0.994063271] [Pastures 1.009595509] 

What I would like to do - is to match the habitats that present themselves in the unique-habitats list with a randomly selected matching habitat in the selection list and then select the highest value to decide where to go.

i.e in pseduocode.

to move_females_test
      let this_step (one-of step_length_lsf / patch-length)
      let available [habitat] of patches in-radius this_step
      let unique-habitats remove-duplicates available
      print available
      print unique-habitats
    
      ifelse length unique-habitats = 1 [
        ; If there is only one unique habitat, move as per the existing code
        set heading (one-of turning_angles_lsf * 100)
        fd this_step
      ] 
[let ratios [foreach habitat in unique-habitats [select one-of habitat in select]
 ;ratio will look like this 
 ;[[Pastures 1] [Arable 0.91]]
 let sorted-ratios sort-by [[- item 1 ?] of ?] ratios
 let highest-ratio first sorted-ratios
 let target-patch one-of patches with [habitat = item 0 highest-ratio] 
 set heading target-patch
 fd this_step
]
      
    end 

Solution

  • I always find lists in a list somehow nasty to handle in NetLogo. Especially in your case where they contain two different variable types. But I think I found a solution to your problem. Not sure if this is the most efficient/concise but...

    to move_females_test
      let this_step (one-of step_length_lsf / patch-length)
      let available [habitat] of patches in-radius this_step
      let unique-habitats remove-duplicates available
      print available
      print unique-habitats
      
      ifelse length unique-habitats = 1 [
        ; If there is only one unique habitat, move as per the existing code
        set heading (one-of turning_angles_lsf * 100)
        fd this_step
      ][
        let best-habitat best-habitat-REP selection unique-habitats
        let target-patch one-of patches in-radius this_step with [habitat = best-habitat]
        set heading target-patch
        fd this_step   
    end
    
    to-report best-habitat-REP [selection unique-habitats]
      ; initallize sperate list for selection habitats and their values
      let selection-habitats []  
      let selection-values []
    
      ; extract habitats and their values from selection into these variables
      foreach selection [
        hab -> 
        set selection-habitats lput item 0 hab selection-habitats
        set selection-values lput item 1 hab selection-values    
      ]
      
      ; initalize a list for the randomly selected habitats from the selection
      let selected-habitats []
      
      ; for each unique habitat
      foreach unique-habitats [
       uhab -> 
        ; we determine the index of all items of the selection that matches (see all-items-REP function below)
        let idx-uhab-in-selection all-items-REP selection-habitats uhab
        ; if at least one entry of the unique habitat exists in the selection
        if not empty? idx-uhab-in-selection [
          ; we randomly pick one from all the matching entries
          set selected-habitats lput one-of idx-uhab-in-selection selected-habitats
        ]    
      ]
      
      ; initialize a list for the values of the selected habitats
      let selected-values []
      
      ; extract the values of the selected habitats from the selection
      foreach selected-habitats [
        current-habitat ->
         set selected-values lput item current-habitat selection-values selected-values
      ]
      
      ; from all these selected values we find the maximum
      let idx-max-value position max selected-values selected-values
      ; and find the according index of this value in the selection
      let final-idx-in-selection item idx-max-value selected-habitats
      
      report item 0 item final-idx-in-selection selection
    end
    
    ;; Helper function to find all elements that match (the item reporter only reports the
    ;;  first matching value)
    to-report all-items-REP [list-to-search item-to-find]
      ; initialize counter
      let i 0
      ; initialize list with indices
      let idx-item []
      ; loop through list
      foreach list-to-search [
        current-list-item -> 
        ; check if value matches, and append its index if it matches
         if current-list-item = item-to-find [set idx-item lput i idx-item]
         set i i + 1
      ]
      report idx-item
    end