我是NetLogo的新手,我正在尝试将NetLogo 5.3.1中构建的模型转换为NetLogo 6.0.3。自动转换器不起作用,所以我试图手动将任务转换为匿名程序。但是,我仍然坚持转换NL-5.3.1代码的以下部分:
let tempNewList [ ] ; to store the new list
(foreach n-values (highest-family-id + 1) [?] [ ; search through all family-ids ever created in model
if count turtles with [family-id = ?] >= 2 [ ; if family-id belongs to 2 or more turtles...
set tempNewList lput ? tempNewList ; ... add to list
]
])
set families tempNewList
这里,目标是更新'家族'全局变量,该变量是至少2个人拥有的家庭ID列表。在NL-6.3.0中打开时,此代码会出现错误:“?未定义”,如预期的那样。
我改名为“?”到eachFamilyID,并使用新的“ - >”匿名过程的语法。例如,我尝试将上面的代码更改为:
let tempNewList [ ]
(foreach n-values (highest-family-id + 1) [ eachFamilyID ->
if count turtles with [family-id = eachFamilyID] >= 2
[set tempNewList lput eachFamilyID tempNewList ] ]
])
set families tempNewList
这给出了错误:'N-VALUES期望这个输入是一个匿名的记者,但是得到了一个匿名命令'。
经过大量阅读transition guide,programming guide,dictionary和大量谷歌搜索,我仍然无法弄清楚如何做到这一点。有什么建议吗?
操作系统:MacOS High Sierra版本10.13.4
答案 0 :(得分:4)
您面临着一个简单的语法问题,但我也认为值得退一步并重新思考您解决问题的方法。让我们从语法开始。
如果您查看未转换的代码,您会注意到顶级结构是这样的:
(foreach n-values (highest-family-id + 1) [?] [ ... ])
此处使用了两个主要基元,foreach
和n-values
,并且它们都采用任务参数。
在foreach
的情况下,该任务是整个[ if count turtles ... ]
块,我在此处已将其[ ... ]
省略。
在n-values
的情况下,该任务只是身份函数[?]
,它只会返回传递给它的任何内容。例如,n-values 5 [?]
会为您提供列表[0 1 2 3 4]
,因为这些列表是?
n-values
传递给其任务参数的连续值。
NetLogo 6中的语法已更改,但n-values
仍需要某种方式来生成连续值。现在看看你的转换版本:
(foreach n-values (highest-family-id + 1) [ eachFamilyID -> ... ])
你能看到失踪的是什么吗?只有一个匿名程序!您对n-values
的调用尝试使用针对foreach
的匿名命令,该命令解释了您收到的错误消息。要解决此问题,您只需在代码中添加NetLogo 6版本的身份功能:
(foreach n-values (highest-family-id + 1) [ n -> n ] [ eachFamilyID -> ... ])
这应该可以解决您当前的问题。
现在让我们退一步。您要做的是构建一个仅包含与特定条件相对应的值的列表。在您的情况下,您只想保留至少有两个成员的家庭的家庭ID。 NetLogo有一个内置的原语,完全可以做到这一点:filter
。这是使用它的一种方法,它与您已经在做的相对接近:
let all-ids n-values (highest-family-id + 1) [ n -> n ]
set families filter [ id ->
count turtles with [ family-id = eachFamilyID ] >= 2
] all-ids
那不是更好吗?但是,它仍然可以改进。首先,NetLogo 6有一个range
原语,您可以经常使用而不是n-values
:
let all-ids range (highest-family-id + 1)
那很整洁。但你也可以这样做:
let all-ids remove-duplicates [ family-id ] of turtles
这有点慢,但仍然可以保证为您提供所有正在使用的家庭ID,并且您可以避免一个人退出一个"错误。
但如果您愿意使用table
扩展程序,则可以采用更简洁的方法。它涉及table:counts
原语。以下是您可以使用它的方法,假设您的代码顶部有extensions [ table ]
:
let counts table:counts [ family-id ] of turtles
set families map first filter [ p -> last p >= 2 ] table:to-list counts
它看起来有点神秘,但它具有比其他方法快得多的优点(一旦你理解它就有点优雅)。让我试着解开一下。
第一行很简单:它使用table:counts
来计算我们所有海龟中每个family-id
的代表次数,这正是我们需要的信息!该信息存储在"表格中。关联"键"有价值的。在这种情况下,每个家庭ID都是一个键,值是它出现的次数。
有了这个,我们需要做的就是进行一些过滤,只保留值至少为2的键。表扩展没有用于过滤表的原语,但我们可以轻松地将表转换为列表,使用table:to-list
,然后过滤该列表。
table:to-list
的结果是列表列表,其中每个子列表都有两个元素,对应于原始表中的键值对。假设我们只有两个家庭,家庭1,有5个成员,家庭2,只有1个成员。我们将得到以下列表:[[1 5] [2 1]]
。够容易!现在,如果我们对此使用filter
,我们只需要保留该对中第二个成员(即last
一个)为>= 2
的子列表。这是上面代码的filter [ p -> last p >= 2 ] ...
部分。
一旦过滤了列表,最后一步就是:我们只想要保留每个子列表的第一个元素。将列表转换为其他内容(这是我们想要在此处执行的操作)通常使用map
原语完成,该原语将记者应用于列表的每个元素并返回结果列表。在这种情况下,我们直接将first
报告者传递给它,但我们也可以使用像[ p -> first p ]
这样的匿名记者。
如果这是我的模特,我会采取完全不同的方法。数字ID是一种难以处理的问题,也是代码中的一个重要错误来源。 NetLogo有更好的方式来表示事物之间的关系。我会创建两个不同的海龟品种:persons
和families
,并在人与他们所属的家庭之间建立联系。获得至少有两名成员的家庭就是:
families with [ count my-links >= 2 ]
更清楚,不是吗?