循环遍历在 Netlogo 中共享共同属性的补丁

Looping through patches that share a common properties in Netlogo

我想总结共享相同 ID 的补丁的一个数字属性 (AT1) 并存储该 ID 的值(下面的过程 simulation)。我的想法是循环遍历补丁以找到共享相同 ID 的补丁(基于外部文件)。

请参阅下面的无法运行的可重现代码,它正在一个接一个地打印所有补丁的总和,但不只是一个 ID,我尝试了几种方法。

globals [
  AT-data
  ABC
  area
  ]

patches-own [
  ID
  AT1
  AT2
  seed
  sum_AT1
]

to setup
  ;; here I just create patches with different values that also appear in the list
  ca
  set ABC [ "A" "B" "C" "D" "E" "F" "G" "H" "I" ]
  ask patches [ set seed random 10 set ID one-of ABC
    ifelse (seed = 4)
    [ set pcolor orange] [set pcolor white]
  ]
end

to load
  reset-timer
  ; first, we load the database file
  ; We check to make sure the file exists first
  ifelse ( file-exists? "AT_data.txt" )
  [
    ; We are saving the data into a list, so it only needs to be loaded once.
    set AT-data []
    file-open "AT_data.txt"
    while [ not file-at-end? ]
    [
      ; file-read gives variables stored in a double list
      ; Each iteration we append the next three-tuple to the current list: ID AT1 AT2
      set AT-data sentence AT-data (list (list file-read file-read file-read))
    ]
    user-message "File loading complete!"
    file-close
   
    assign-data
    stop
    ]
  [ user-message "There is no AT_data.txt file in current directory!" ]

  file-close-all

  print timer
end


to assign-data
  reset-timer
  ask patches with [seed = 4] [
    let i 1
    while [i < length AT-data] [
      let current-inner-list item i AT-data
      ifelse (ID = item 0 current-inner-list)
        [ set AT1 item 1 current-inner-list set AT2 item 2 current-inner-list
          stop]
        [ set i i + 1 ]
      ]
      ]
  print timer
end


to simulation
  reset-timer
  ask patches [
    let i 1
    while [i < length AT-data] [
      let current-inner-list item i AT-data
      ifelse (ID = item 0 current-inner-list)
     
     ;; I tried with and without this following line
      ;[ask patches with [ID = item 0 current-inner-list] [
      [ set area  area + AT1
        print area
        print ID
        stop
        ]
      ;]
      
    ;; this one is an alternative
       ;[ print sum [AT1] of patches with [ID = item 0 current-inner-list]
       ;print ID
       ;]
      [ set i i + 1 ]
      ]
  ]

  print timer
end

AT_data.txt 是

   "A"      65      81
   "B"      21      71
   "C"      54      18
   "D"      23      41
   "E"      85      27
   "F"      35      88
   "G"      29       4
   "H"      78       2
   "I"      99      60

感谢您的宝贵时间!

我的第一句话是你有补丁在 simulation 中再次询问补丁。

您的第二个解决方案使用起来更简单。这里最主要的是把它从补丁上下文中取出来,让观察者 运行 它。 对于打印输出,我建议使用 print (word current-ID ": " current-sum) 等格式。当你想在 运行 模型后快速检查它时,这会更清晰。

to simulation-2
  reset-timer
  
  let i 0
  while [i < length AT-data] [
    let current-inner-list item i AT-data
    let current-ID item 0 current-inner-list
    let current-sum sum [AT1] of patches with [ID = current-ID]
    print (word current-ID ": " current-sum)
    
    set i i + 1 
  ]
  
  print timer
end

对于您的第一个解决方案,您的问题是您只有一个递增的区域变量。在下面的例子中,我把area做成一个列表,长度和AT-data一样,包含列表。每个内部列表都包含一个 ID 和一个设置为 0 [["A" 0] ["B" 0] ... ["I" 0]] 的计数器。 为此,我使用 map 过程。 map 获取列表的每个单独元素,对其进行特定操作,然后 return 将它们全部作为一个新列表。总的来说,这是一个非常有用的过程,可以帮助您了解何时将使用列表。

接下来我像您一样遍历所有补丁并增加我的区域列表的计数器以获得正确的 ID。我有这个递增的两个不同版本。第一个有很多局部变量来清楚地展示它是如何工作的。你挖掘出正确的子列表,然后挖掘出正确的变量,递增该变量,在子列表中替换它并替换主列表中的子列表。第二个完全相同,但在一行代码中。

to simulation-1
  reset-timer
  
  set area map [inner-list -> list item 0 inner-list 0] AT-data ;creates a new list of lists of the form [["A" 0] ["B" 0] ... ].
  
  ask patches [
    let i 0
    while [i < length AT-data] [
      let current-inner-list item i AT-data
      ifelse (ID = item 0 current-inner-list)
      [ let inner-area-list item i area    ;grab the correct innerlist
        let increased-count item 1 inner-area-list + AT1    ;increment the second part of this inner list
        set inner-area-list replace-item 1 inner-area-list increased-count    ;put the incremented count back into the inner list
        set area replace-item i area inner-area-list    ;put the inner list back into the complete list
        
        ;; all these can be combined into a single line of code but that is more prone to errors
        ;set area replace-item i area (replace-item 1 item i area (item 1 item i area + AT1))
        
        stop
      ]
      [ set i i + 1 ]
    ]
  ]
  print area
  
  print timer
end

只有在制作了整个嵌套列表结构之后,我才想到您可以使用普通列表来完成,其中您只有不同的计数器而不是 ID,但这种结构确实使它非常紧凑并且清晰易用,便于后续处理。