NetLogo 5 到 6 的转换:for 循环
NetLogo 5 to 6 transition: for loop
我是 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
这里,objective 是更新 'families' 全局变量,它是一个至少有 2 个人持有的家庭 ID 列表。当在 NL-6.3.0 中打开时,此代码如预期的那样给出错误:“? is undefined”。
我重命名为“?”到每个 FamilyID,并为匿名过程使用新的“->”语法。例如,我尝试将上面的代码更改为:
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 expected this input to be an anonymous reporter, but got an anonymous command instead'。
在大量阅读 transition guide, programming guide, dictionary 和谷歌搜索之后,我仍然不知道该怎么做。有什么建议吗?
操作系统: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 版本的身份函数:
(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,并且您可以避免出现 "off by one" 错误的可能性。
但是如果您愿意使用 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
在我们所有的海龟中出现了多少次,这正是我们需要的信息!此信息存储在 "table" 中,它将 "keys" 与值相关联。在这种情况下,每个家庭ID是一个键,值是它出现的次数。
一旦我们有了它,我们需要做的就是进行一些过滤以仅保留值至少为 2 的键。table 扩展没有过滤原语 tables , 但我们可以使用 table:to-list
轻松地将 table 转换为列表,然后过滤该列表。
table:to-list
的结果是一个列表的列表,其中每个子列表有两个元素,对应于原始table中的键值对。假设我们只有两个家庭,家庭 1 有 5 个成员,家庭 2 只有 1 个成员。我们将得到以下列表:[[1 5] [2 1]]
。很简单!现在,如果我们在此使用 filter
,我们只需要保留该对的第二个成员(即 last
之一)为 >= 2
的子列表。那是上面代码的 filter [ p -> last p >= 2 ] ...
部分。
过滤列表后,还有最后一步:我们只需要我们保留的每个子列表的第一个元素。将列表转换为其他内容(这是我们在这里想要做的)通常由 map
primitive, which takes a reporter, applies it to each element of the list and returns the resulting list. In this case we directly pass it the first
报告者完成,但我们也可以使用匿名报告者,如 [ p -> first p ]
.
但是,如果这是我的模型,我会采取完全不同的方法。数字 ID 很难处理,并且是代码错误的一大来源。 NetLogo 有更好的方式来表示事物之间的关系。我会创建两种不同的海龟品种:persons
和 families
,并在个人和他们所属的家庭之间建立联系。获得至少有两名成员的家庭将是:
families with [ count my-links >= 2 ]
更清楚了,不是吗?
我是 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
这里,objective 是更新 'families' 全局变量,它是一个至少有 2 个人持有的家庭 ID 列表。当在 NL-6.3.0 中打开时,此代码如预期的那样给出错误:“? is undefined”。
我重命名为“?”到每个 FamilyID,并为匿名过程使用新的“->”语法。例如,我尝试将上面的代码更改为:
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 expected this input to be an anonymous reporter, but got an anonymous command instead'。
在大量阅读 transition guide, programming guide, dictionary 和谷歌搜索之后,我仍然不知道该怎么做。有什么建议吗?
操作系统: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 版本的身份函数:
(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,并且您可以避免出现 "off by one" 错误的可能性。
但是如果您愿意使用 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
在我们所有的海龟中出现了多少次,这正是我们需要的信息!此信息存储在 "table" 中,它将 "keys" 与值相关联。在这种情况下,每个家庭ID是一个键,值是它出现的次数。
一旦我们有了它,我们需要做的就是进行一些过滤以仅保留值至少为 2 的键。table 扩展没有过滤原语 tables , 但我们可以使用 table:to-list
轻松地将 table 转换为列表,然后过滤该列表。
table:to-list
的结果是一个列表的列表,其中每个子列表有两个元素,对应于原始table中的键值对。假设我们只有两个家庭,家庭 1 有 5 个成员,家庭 2 只有 1 个成员。我们将得到以下列表:[[1 5] [2 1]]
。很简单!现在,如果我们在此使用 filter
,我们只需要保留该对的第二个成员(即 last
之一)为 >= 2
的子列表。那是上面代码的 filter [ p -> last p >= 2 ] ...
部分。
过滤列表后,还有最后一步:我们只需要我们保留的每个子列表的第一个元素。将列表转换为其他内容(这是我们在这里想要做的)通常由 map
primitive, which takes a reporter, applies it to each element of the list and returns the resulting list. In this case we directly pass it the first
报告者完成,但我们也可以使用匿名报告者,如 [ p -> first p ]
.
但是,如果这是我的模型,我会采取完全不同的方法。数字 ID 很难处理,并且是代码错误的一大来源。 NetLogo 有更好的方式来表示事物之间的关系。我会创建两种不同的海龟品种:persons
和 families
,并在个人和他们所属的家庭之间建立联系。获得至少有两名成员的家庭将是:
families with [ count my-links >= 2 ]
更清楚了,不是吗?