4

在 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)
4

3 回答 3

3

UNIQUE 和其他集合操作中的相等检查的实现似乎是Cmp_Value,并且进行比较的方式是减去对象的帧指针。如果减法为零(例如,这些是 SAME? 对象),则比较被视为匹配:

f-series.c 第 283 行,R3-Alpha 开源发布

如果您查看周围的代码,您会在同一例程中看到对 Cmp_Block 的调用。在 Cmp_Block 的情况下,它进行递归比较,并尊重区分大小写......因此块和对象的行为方式之间的区别:

f-series.c 中的 Cmp_Block()

鉴于它是这样编写的,如果您希望 UNIQUE 操作基于对象与其身份的逐字段比较,除了编写自己的例程并调用 EQUAL?...或修改 C 代码。

这是一个不需要更改 C 源代码的简短技巧,它在 UNIQUE 的输出上执行 MAP-EACH。身体过滤掉任何 EQUAL?已经看到的对象(因为当 MAP-EACH 的主体返回未设置时,它不会向结果添加任何内容):

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!而不是地图!随时随地跟踪对象,因为 MAP!目前不允许对象作为键。如果他们允许它,他们可能会遇到相同的问题,即不将字段相等的对象散列相同。

(注意:修复这个问题和其他问题在 Ren-C 分支的雷达上,除了现在是具有基本修复的最快的 Rebol 解释器之外,还对集合操作进行了一些增强聊天中的讨论)

于 2015-11-06T23:33:18.820 回答
2

平等的?和相同?仅当对象是相同的对象引用时才为对象返回 true。我写了一个函数来检查对象之间的相似性,如果两个对象具有相同的单词、相同的值和相同的类型,它会返回 true:

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

你可以在你的情况下使用它。

于 2015-11-09T13:52:07.233 回答
2
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
]
于 2015-11-20T21:26:23.723 回答