2015-11-06 103 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 
]