从 Rebol 中的系列中删除重复对象
Remove duplicate objects from series in Rebol
在 R2 和 R3 中,我可以使用 unique
删除系列中的重复项目:
>> a: [1 2 2 3]
>> length? a
== 4
>> length? unique a
== 3
如何对一系列对象执行相同的操作?例如,
b: reduce [
make object! [a: 1]
make object! [b: 2]
make object! [b: 2]
make object! [c: 3]
]
>> length? b
== 4
>> length? unique b
== 4 ; (I'd like it to be 3)
UNIQUE和其他集合操作中的相等性检查的实现似乎是Cmp_Value
,比较的方式是减去object的帧指针。如果该减法为零(例如,这些是相同的?object),则比较被视为匹配:
f-series.c Line 283, R3-Alpha open source release
如果您查看周围的代码,您会在同一例程中看到对 Cmp_Block 的调用。在 Cmp_Block 的情况下,它进行递归比较,并区分大小写......因此块和 objects 的行为方式之间的差异:
鉴于它是这样写的,如果你希望一个 UNIQUE 操作基于 field-by-field 比较 objects 与他们的身份,除了写之外没有办法做到这一点您自己的例程并调用 EQUAL?...或修改 C 代码。
这是一个不需要更改 C 源代码的简短 hack,它对 UNIQUE 的输出进行 MAP-EACH。 body 过滤掉任何 EQUAL? object 已经看到(因为当 MAP-EACH returns 的 body 未设置时,它不会对结果添加任何内容):
my-unique: function [array [block!]] [
objs: copy []
map-each item unique array [
if object? :item [
foreach obj objs [
if equal? item obj [unset 'item break]
]
unless unset? :item [append objs item]
]
:item ;-- if unset, map-each adds nothing to result
]
]
很遗憾,您必须使用 BLOCK!而不是地图!随时跟踪 objects,因为 MAP!目前不允许 objects 作为键。如果他们允许的话,他们可能会遇到同样的问题,即不对 field-equal object 进行哈希处理。
(注意:Ren-C 分支正在关注解决这个问题和其他问题,此外,fundamental fixes, also has a bit of enhancements to the set operations. Discussions in chat 分支现在是最快的 Rebol 解释器)
相等?和一样? returns 仅当对象是相同的对象引用时才为真。
我写了一个函数来检查对象之间的相似性,如果两个对象具有相同的值和相同类型的相同单词,它 returns 为真:
similar?: func [
{Returns true if both object has same words in same types.}
o [object!] p [object!] /local test
][
test: [if not equal? type? get in o word type? get in p word [return false]]
foreach word sort first o test
foreach word sort first p test
true
]
您可以进行如下测试:
>> o: make object! [b: 2]
>> p: make object! [b: 2]
>> equal? o p
== false
>> same? o p
== false
>> similar? o p
== true
你可以在你的情况下使用它。
unique+: func [array [block!]] [
objs: copy []
map-each item unique array [
if object? :item [
foreach obj objs [
if equal-object? :item :obj [unset 'item break]
]
if value? 'item [append objs item]
]
;-- If unset, map-each adds nothing to result under R3.
; R2 behaves differently. This works for both.
either value? 'item [:item] [()]
]
]
equal-object?: func [
"Returns true if both objects have same words and values."
o [object!] p [object!]
][
if not equal? sort words-of o sort words-of p [return false]
foreach word words-of o [
if not equal? o/:word p/:word [return false]
]
true
]
在 R2 和 R3 中,我可以使用 unique
删除系列中的重复项目:
>> a: [1 2 2 3]
>> length? a
== 4
>> length? unique a
== 3
如何对一系列对象执行相同的操作?例如,
b: reduce [
make object! [a: 1]
make object! [b: 2]
make object! [b: 2]
make object! [c: 3]
]
>> length? b
== 4
>> length? unique b
== 4 ; (I'd like it to be 3)
UNIQUE和其他集合操作中的相等性检查的实现似乎是Cmp_Value
,比较的方式是减去object的帧指针。如果该减法为零(例如,这些是相同的?object),则比较被视为匹配:
f-series.c Line 283, R3-Alpha open source release
如果您查看周围的代码,您会在同一例程中看到对 Cmp_Block 的调用。在 Cmp_Block 的情况下,它进行递归比较,并区分大小写......因此块和 objects 的行为方式之间的差异:
鉴于它是这样写的,如果你希望一个 UNIQUE 操作基于 field-by-field 比较 objects 与他们的身份,除了写之外没有办法做到这一点您自己的例程并调用 EQUAL?...或修改 C 代码。
这是一个不需要更改 C 源代码的简短 hack,它对 UNIQUE 的输出进行 MAP-EACH。 body 过滤掉任何 EQUAL? object 已经看到(因为当 MAP-EACH returns 的 body 未设置时,它不会对结果添加任何内容):
my-unique: function [array [block!]] [
objs: copy []
map-each item unique array [
if object? :item [
foreach obj objs [
if equal? item obj [unset 'item break]
]
unless unset? :item [append objs item]
]
:item ;-- if unset, map-each adds nothing to result
]
]
很遗憾,您必须使用 BLOCK!而不是地图!随时跟踪 objects,因为 MAP!目前不允许 objects 作为键。如果他们允许的话,他们可能会遇到同样的问题,即不对 field-equal object 进行哈希处理。
(注意:Ren-C 分支正在关注解决这个问题和其他问题,此外,fundamental fixes, also has a bit of enhancements to the set operations. Discussions in chat 分支现在是最快的 Rebol 解释器)
相等?和一样? returns 仅当对象是相同的对象引用时才为真。 我写了一个函数来检查对象之间的相似性,如果两个对象具有相同的值和相同类型的相同单词,它 returns 为真:
similar?: func [
{Returns true if both object has same words in same types.}
o [object!] p [object!] /local test
][
test: [if not equal? type? get in o word type? get in p word [return false]]
foreach word sort first o test
foreach word sort first p test
true
]
您可以进行如下测试:
>> o: make object! [b: 2]
>> p: make object! [b: 2]
>> equal? o p
== false
>> same? o p
== false
>> similar? o p
== true
你可以在你的情况下使用它。
unique+: func [array [block!]] [
objs: copy []
map-each item unique array [
if object? :item [
foreach obj objs [
if equal-object? :item :obj [unset 'item break]
]
if value? 'item [append objs item]
]
;-- If unset, map-each adds nothing to result under R3.
; R2 behaves differently. This works for both.
either value? 'item [:item] [()]
]
]
equal-object?: func [
"Returns true if both objects have same words and values."
o [object!] p [object!]
][
if not equal? sort words-of o sort words-of p [return false]
foreach word words-of o [
if not equal? o/:word p/:word [return false]
]
true
]