Remove duplicate objects from a series in Rebol

In R2 and R3, I can use uniqueto remove duplicate items from a series:

>> a: [1 2 2 3]
>> length? a
== 4
>> length? unique a
== 3

How can I perform the same operation on a series of objects? eg.

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
source share
3 answers

The implementation of equality checking in UNIQUE and other set operations looks like Cmp_Value, and the comparison method is to subtract pointers to object frames. If this subtraction is zero (for example, is this a SAME object?), Then the comparison is considered a match:

f-series.c Line 283, R3-Alpha Open Source Release

, Cmp_Block . Cmp_Block ... , , :

Cmp_Block() f-series.c

, , , UNIQUE , , EQUAL?... C.

, C, MAP-EACH UNIQUE. 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
    ]
]

, ! MAP! , , MAP! . , , , , .

(. Ren-C, Rebol , . chat)

+3

? SAME? 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

.

+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
]
+2
source

Source: https://habr.com/ru/post/1614809/


All Articles