netlogo - NetLogo 5 到 6 过渡:for 循环
问题描述
我对 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 期望此输入是匿名报告者,但得到了一个匿名命令'。
经过大量阅读过渡指南、编程指南、字典和大量谷歌搜索后,我仍然无法弄清楚如何做到这一点。有什么建议么?
操作系统:MacOS High Sierra 版本 10.13.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 版本的 identity 函数:
(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 ]
更清楚,不是吗?
推荐阅读
- angular - angular 6 post **array data** using `httpClient`方法不适用于asp.net核心API
- spring-boot - 在 Spring Boot 应用程序中忽略状态为 302 的 HTTP 响应的 Set-cookie
- angular - 返回时路由返回空白页面,但在Angular 7应用程序中的页面刷新时加载
- c - 从输入 [Core Dump (Segmentation fault)] 在数组中插入元素
- linux - 在 Linux 中等待多线程事件的最佳实践(如 WaitForMultipleObjects)
- c++ - 如何使用 IOServiceOpenAsFileDescriptor?
- mysql - 在 MySQL 中获取每月的总费用
- types - 如何在 Perl 6 中为参数类型创建自定义元模型?
- spring - Springboot 和 maven:如何使用两个配置文件自动启动单元测试
- asp.net - 压缩 Azure 存储文件并从 Web Api 返回文件