循环遍历在 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,但这种结构确实使它非常紧凑并且清晰易用,便于后续处理。
我想总结共享相同 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,但这种结构确实使它非常紧凑并且清晰易用,便于后续处理。