如何在 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

更简洁的方法使用 filterthis 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 = 2017varA = 7varB = 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感兴趣,还需要两步:

  1. 使用firstlastitem 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];
  2. 正在使用 lastitem 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 将包含补丁可以具有的 yearvarAvarB 的任何可能组合,那么就没有问题。否则,您可能需要预料到这种可能性,并使用 ifelseifelse-valuetemp-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。

旁注

  1. 您是否有意在 year = 0varA = 0 上留下一些补丁?因为,在你的 setup 中,你只使用 strictly-greater 和 strictly-less 符号 - 所以所有带有 pxcor = 3 的补丁都不会设置 year 和所有pyxcor = -6 的补丁不会设置 varA.
  2. 为了风格精确,我建议选择不需要大写字母的显着变量名:如果你检查任何补丁,你会看到例如 varA 只是 vara对于 NetLogo。