2015-11-06 80 views
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) 

回答

3

在UNIQUE和另一组操作所述相等性检查的实施似乎是Cmp_Value,并且比较被完成的方式是要减去的对象的帧的指针。如果减为零(例如,这些都是同一个对象?)则比较被认为是匹配:

f-series.c Line 283, R3-Alpha open source release

如果你看看周围的代码,你会看到同样的程序来Cmp_Block通话。在Cmp_Block的情况下,它不会递归比较,和荣誉的大小写......所以之间的差异如何块和对象行为:

Cmp_Block() in f-series.c

由于它被写了,如果你想一个UNIQUE操作是基于对象与其身份的字段逐场比较,除了编写自己的例程并调用EQUAL?或修改C代码外,没有办法做到这一点。

这是一个短暂的黑客攻击,不需要改变C源代码,它在UNIQUE的输出上执行MAP-EACH。身体过滤出任何平等?已经被看到(因为当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!目前不允许对象作为键。如果他们允许的话,他们可能会遇到同样的问题,即不对散列字段相同的对象进行散列。

(注:要解决这个和其他问题上的任-C的分支,其中除了目前是最快的Rebol解释器fundamental fixes的雷达,也有一点enhancements to the set operations讨论,chat

+0

只是想添加一个注意,这是仅R3,但在那里工作很好。感谢你的回答! –

2

EQUAL?和SAME?仅当对象是相同的对象引用时才返回对象。

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 

您可以使用 我写了一个函数来检查对象之间的相似性,但如果两个对象有相同的价值观和相同类型相同的话返回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 
]