如何在 Netlogo 中的列表中使用列表值
How to use list values inside lists in Netlogo
当我设置我的模型时,我还上传了一个包含多个列的 csv 文件,经过一些研究,我发现它被读取为列表列表(每一行都是一个列表)。
set yield-data sentence yield-data (list (list file-read file-read file-read file-read file-read))
当我运行模型(土地利用模型)时,对于每个补丁,列表列表中的值(yield-data
来自上面)必须用于一个简单的算术,它将定义它的下一个土地利用类别。
我还没有,我首先要弄清楚如何在 my-list
中查找值
请参阅下面的可重现代码,使用 my-list
而不是 yield-data
,除了我为之苦苦挣扎的过程 to test
。我还是面向对象建模的新手...
globals [
my-list
my-rd-list
]
patches-own [
year
varA
varB
temp-varC
]
to setup
;; here I just create patches with different values that also appear in the list
ca
resize-world 9 * 0 ( 9 * 1 ) ( 9 * -1 ) 9 * 0
set my-list [[2015 3 2 8] [2016 5 1 10] [2017 7 0 12]]
ask patches with [pxcor < 3] [set year 2015]
ask patches with [pxcor > 3] [ set year 2016]
ask patches with [pxcor > 6] [ set year 2017]
ask patches with [pycor > -3] [ set varA 3]
ask patches with [pycor < -3] [ set varA 5]
ask patches with [pycor < -6] [set varA 7]
ask patches [set varB random 3]
end
to test
;; need to add a "while n <= number of list inside the list"
let n 1
foreach item n my-list [
x ->
ask patches with [year = item 0 item n my-list and varA = item 1 item n my-list and varB = item 2 item n my-list] [set pcolor orange set temp-varC item 3 item n my-list]
set n n + 1
]
end
这个想法是,对于每个列表(例如 [2015 3 2 8],列表的最后一个值用于之后对修补具有 year = 2015 的标准的补丁进行小数学运算,varA = 3 和 varB=2,我认为将它作为临时变量存储在补丁中会更容易。由于更好地理解 ,代码现在可以工作了。
然而,
1) 但是我不知道如何计算主列表中有多少列表 - 或者我在开头提到的原始 txt 文件中有多少行。
2) 我希望 varA 在里面,比方说,-1 / + 1 围绕 item 1 item n my-list
的值,像下面这样的东西不起作用
ask patches with [year = item 0 item n my-list and varA < item 1 + 1 (item n my-list) and varA > item 1 - 1 (item n my-list) and varB = item 2 item n my-list] [set pcolor orange set temp-varC item 3 item n my-list]
然后我有一个“基本”问题:当检查一个补丁时,他的 temp-varC
更新并且 varA
也根据值更新在 my-list
中:在 temp-varC
的下一次更新的那个循环中它仍然可以被忽略吗?因为 varA 会改变,所以“项目”的组合也会改变,它可以更新 temp-varC
(但我不想要那个!)。
关于如何计算my-list
中有多少列表
每个内部列表只是my-lists
的一个项目,所以length my-lists
会告诉你有多少个内部列表。
在varA
左右区间
这只需要你设计一个算术条件来反映你想要的。我想这至少可以通过几种方式来完成。
例如,对于您要应用此间隔的条件,而不是像这样的条件:
varA = item 1 some-list
你可以拥有:
abs (varA - item 1 some-list) <= 1
方法使用 while
首先让我使用 while
为您提供一个解决方案,因为这是您解决问题的方式,而且有助于阐明在此上下文中如何处理列表。
之后,更简洁的方法使用 filter
.
使用 while
方法,您不需要 foreach
,因为 foreach
runs a command for every item of a list。在您的示例中,您使用 foreach
,您是在告诉您的匿名过程将 my-list
的每个项目(即每个内部列表)一次存储为 x
,并且 运行 每个 x
的一些命令。但是,您永远不会在此类命令中解决 x
,这证明 foreach
是多余的。
这意味着,使用上面关于列表的长度和条件中的间隔的两条信息,您只需执行以下操作即可实现您的目标:
to test
ask patches [
let i 0
while [i < length my-list] [
let current-inner-list item i my-list
ifelse ((year = item 0 current-inner-list) AND (abs (varA - item 1 current-inner-list) <= 1) AND (varB = item 2 current-inner-list))
[set temp-varC item 3 current-inner-list
stop]
[set i i + 1]
]
]
end
这样,循环将检查内部列表,直到找到正确的列表,然后设置 temp-varC
,然后执行 stop
,这样循环就结束了,而不必遍历所有 my-list
.
请注意,围绕单个布尔值的括号是可选的,我使用它们是为了提高可读性。
方法使用filter
更简洁的方法使用 filter
:this primitive 将报告者和列表作为参数,并且 returns(reports,在NetLogo 行话)仅包含原始列表中报告者评估为 TRUE
.
的项目的列表
对于您的情况,这意味着您可以:
to test
ask patches [
set temp-varC last (first (filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list))
]
end
让我们分解这段代码。
filter
命令被传递给匿名报告者(条件的通常串联)和 my-list
,因此它将仅报告 my-list
的项目,所有这些条件评估为 TRUE
.
例如:对于具有year = 2017
、varA = 7
和varB = 0
的补丁,filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list
语句将报告[[2017 7 0 12]]
,即my-list
但只包含那一项。
鉴于你只对提取12感兴趣,还需要两步:
- 使用
first
或last
或item 0
提取唯一的内部列表。因此 first (filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list)
报告 [2017 7 0 12]
;
- 正在使用
last
或 item 3
提取此内部列表的最后一项。因此 last (first (filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list))
报告 12
.
这就是为什么 set temp-varC <all of the above>
能做到这一点。
注意: 带有 filter
的代码当前不适用于您的示例,因为 my-list
当前不包含足够的值组合来涵盖所有补丁。这意味着,对于某些补丁,filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list
将报告一个空列表 []
,因此 运行ning first (filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list)
会给您一个错误。如果在真实模型中,my-list
将包含补丁可以具有的 year
、varA
和 varB
的任何可能组合,那么就没有问题。否则,您可能需要预料到这种可能性,并使用 ifelse
或 ifelse-value
为 temp-varC
分配默认值,以防在 my-list
中找不到匹配列表。类似于:
to test
ask patches [
let my-list-filtered filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list
set temp-varC ifelse-value (empty? my-list-filtered) [0.5] [last first my-list-filtered]
]
end
关于 temp-varC
的多次更新
否:ask
在 NetLogo 中的工作方式是,它首先收集属于被召唤的代理集的所有代理,然后要求每个代理执行命令块中的操作。就是这样,没有代理集的动态更新。
这段代码验证了它:
to test-ask-command
clear-all
create-turtles 2 [
set color 25
]
ask turtles with [color = 25] [
show "Hi!"
ask other turtles [
set color 35
]
]
end
命令中心显示以下内容:
observer> test-ask-command
(turtle 1): "Hi!"
(turtle 0): "Hi!"
这意味着第二只乌龟打招呼,即使在它开始执行动作时,它的颜色已经变为 35。
旁注
- 您是否有意在
year = 0
和 varA = 0
上留下一些补丁?因为,在你的 setup
中,你只使用 strictly-greater 和 strictly-less 符号 - 所以所有带有 pxcor = 3
的补丁都不会设置 year
和所有pyxcor = -6
的补丁不会设置 varA
.
- 为了风格精确,我建议选择不需要大写字母的显着变量名:如果你检查任何补丁,你会看到例如
varA
只是 vara
对于 NetLogo。
当我设置我的模型时,我还上传了一个包含多个列的 csv 文件,经过一些研究,我发现它被读取为列表列表(每一行都是一个列表)。
set yield-data sentence yield-data (list (list file-read file-read file-read file-read file-read))
当我运行模型(土地利用模型)时,对于每个补丁,列表列表中的值(yield-data
来自上面)必须用于一个简单的算术,它将定义它的下一个土地利用类别。
我还没有,我首先要弄清楚如何在 my-list
请参阅下面的可重现代码,使用 my-list
而不是 yield-data
,除了我为之苦苦挣扎的过程 to test
。我还是面向对象建模的新手...
globals [
my-list
my-rd-list
]
patches-own [
year
varA
varB
temp-varC
]
to setup
;; here I just create patches with different values that also appear in the list
ca
resize-world 9 * 0 ( 9 * 1 ) ( 9 * -1 ) 9 * 0
set my-list [[2015 3 2 8] [2016 5 1 10] [2017 7 0 12]]
ask patches with [pxcor < 3] [set year 2015]
ask patches with [pxcor > 3] [ set year 2016]
ask patches with [pxcor > 6] [ set year 2017]
ask patches with [pycor > -3] [ set varA 3]
ask patches with [pycor < -3] [ set varA 5]
ask patches with [pycor < -6] [set varA 7]
ask patches [set varB random 3]
end
to test
;; need to add a "while n <= number of list inside the list"
let n 1
foreach item n my-list [
x ->
ask patches with [year = item 0 item n my-list and varA = item 1 item n my-list and varB = item 2 item n my-list] [set pcolor orange set temp-varC item 3 item n my-list]
set n n + 1
]
end
这个想法是,对于每个列表(例如 [2015 3 2 8],列表的最后一个值用于之后对修补具有 year = 2015 的标准的补丁进行小数学运算,varA = 3 和 varB=2,我认为将它作为临时变量存储在补丁中会更容易。由于更好地理解
1) 但是我不知道如何计算主列表中有多少列表 - 或者我在开头提到的原始 txt 文件中有多少行。
2) 我希望 varA 在里面,比方说,-1 / + 1 围绕 item 1 item n my-list
的值,像下面这样的东西不起作用
ask patches with [year = item 0 item n my-list and varA < item 1 + 1 (item n my-list) and varA > item 1 - 1 (item n my-list) and varB = item 2 item n my-list] [set pcolor orange set temp-varC item 3 item n my-list]
然后我有一个“基本”问题:当检查一个补丁时,他的 temp-varC
更新并且 varA
也根据值更新在 my-list
中:在 temp-varC
的下一次更新的那个循环中它仍然可以被忽略吗?因为 varA 会改变,所以“项目”的组合也会改变,它可以更新 temp-varC
(但我不想要那个!)。
关于如何计算my-list
中有多少列表
每个内部列表只是my-lists
的一个项目,所以length my-lists
会告诉你有多少个内部列表。
在varA
左右区间
这只需要你设计一个算术条件来反映你想要的。我想这至少可以通过几种方式来完成。
例如,对于您要应用此间隔的条件,而不是像这样的条件:
varA = item 1 some-list
你可以拥有:
abs (varA - item 1 some-list) <= 1
方法使用 while
首先让我使用 while
为您提供一个解决方案,因为这是您解决问题的方式,而且有助于阐明在此上下文中如何处理列表。
之后,更简洁的方法使用 filter
.
使用 while
方法,您不需要 foreach
,因为 foreach
runs a command for every item of a list。在您的示例中,您使用 foreach
,您是在告诉您的匿名过程将 my-list
的每个项目(即每个内部列表)一次存储为 x
,并且 运行 每个 x
的一些命令。但是,您永远不会在此类命令中解决 x
,这证明 foreach
是多余的。
这意味着,使用上面关于列表的长度和条件中的间隔的两条信息,您只需执行以下操作即可实现您的目标:
to test
ask patches [
let i 0
while [i < length my-list] [
let current-inner-list item i my-list
ifelse ((year = item 0 current-inner-list) AND (abs (varA - item 1 current-inner-list) <= 1) AND (varB = item 2 current-inner-list))
[set temp-varC item 3 current-inner-list
stop]
[set i i + 1]
]
]
end
这样,循环将检查内部列表,直到找到正确的列表,然后设置 temp-varC
,然后执行 stop
,这样循环就结束了,而不必遍历所有 my-list
.
请注意,围绕单个布尔值的括号是可选的,我使用它们是为了提高可读性。
方法使用filter
更简洁的方法使用 filter
:this primitive 将报告者和列表作为参数,并且 returns(reports,在NetLogo 行话)仅包含原始列表中报告者评估为 TRUE
.
对于您的情况,这意味着您可以:
to test
ask patches [
set temp-varC last (first (filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list))
]
end
让我们分解这段代码。
filter
命令被传递给匿名报告者(条件的通常串联)和 my-list
,因此它将仅报告 my-list
的项目,所有这些条件评估为 TRUE
.
例如:对于具有year = 2017
、varA = 7
和varB = 0
的补丁,filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list
语句将报告[[2017 7 0 12]]
,即my-list
但只包含那一项。
鉴于你只对提取12感兴趣,还需要两步:
- 使用
first
或last
或item 0
提取唯一的内部列表。因此first (filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list)
报告[2017 7 0 12]
; - 正在使用
last
或item 3
提取此内部列表的最后一项。因此last (first (filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list))
报告12
.
这就是为什么 set temp-varC <all of the above>
能做到这一点。
注意: 带有 filter
的代码当前不适用于您的示例,因为 my-list
当前不包含足够的值组合来涵盖所有补丁。这意味着,对于某些补丁,filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list
将报告一个空列表 []
,因此 运行ning first (filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list)
会给您一个错误。如果在真实模型中,my-list
将包含补丁可以具有的 year
、varA
和 varB
的任何可能组合,那么就没有问题。否则,您可能需要预料到这种可能性,并使用 ifelse
或 ifelse-value
为 temp-varC
分配默认值,以防在 my-list
中找不到匹配列表。类似于:
to test
ask patches [
let my-list-filtered filter [current-inner-list -> (item 0 current-inner-list = year) AND (abs (varA - item 1 current-inner-list) <= 1) AND (item 2 current-inner-list = varB)] my-list
set temp-varC ifelse-value (empty? my-list-filtered) [0.5] [last first my-list-filtered]
]
end
关于 temp-varC
的多次更新
否:ask
在 NetLogo 中的工作方式是,它首先收集属于被召唤的代理集的所有代理,然后要求每个代理执行命令块中的操作。就是这样,没有代理集的动态更新。
这段代码验证了它:
to test-ask-command
clear-all
create-turtles 2 [
set color 25
]
ask turtles with [color = 25] [
show "Hi!"
ask other turtles [
set color 35
]
]
end
命令中心显示以下内容:
observer> test-ask-command
(turtle 1): "Hi!"
(turtle 0): "Hi!"
这意味着第二只乌龟打招呼,即使在它开始执行动作时,它的颜色已经变为 35。
旁注
- 您是否有意在
year = 0
和varA = 0
上留下一些补丁?因为,在你的setup
中,你只使用 strictly-greater 和 strictly-less 符号 - 所以所有带有pxcor = 3
的补丁都不会设置year
和所有pyxcor = -6
的补丁不会设置varA
. - 为了风格精确,我建议选择不需要大写字母的显着变量名:如果你检查任何补丁,你会看到例如
varA
只是vara
对于 NetLogo。