2013-10-16 16 views
4

自定義對象我有一個類大致是這樣的:Set.include?使用Ruby

class C 
    attr_accessor :board # board is a multidimensional array (represents a matrix) 

    def initialize 
     @board = ... # initialize board 
    end 

    def ==(other) 
     @board == other.board 
    end 
end 

然而,當我這樣做:

s = Set.new 
s.add(C.new) 
s.include?(C.new) # => false 

爲什麼?

回答

2

Set使用eql?hash而不是==來測試兩個對象是否相等。例如,請參閱this documentation of Set:「由於Set使用散列作爲存儲,因此每對元素的相等性根據Object#eql?和Object#散列確定。」

如果您希望兩個不同的C對象對於設置成員資格是相同的,則必須重寫這兩個方法。

class C 
    attr_accessor :board 

    def initialize 
    @board = 12 
    end 

    def eql?(other) 
    @board == other.board 
    end 

    def hash 
    @board.hash 
    end 
end 

s = Set.new 
s.add C.new 
s.include? C.new # => true 
+0

你試過了嗎?我做了,沒有工作。 – steenslag

+0

好點 - 我認爲我們也需要'哈希'。更正... –

+0

我upvoted,但接受steenslag的答案,因爲它顯示'eql?'不是由Hash調用,這對我很有趣。不管怎樣,謝謝你。 – whatyouhide

1

你需要做以下事情:

require 'set' 
class C 
    attr_accessor :board 

    def initialize 
    @board = 12 
    end 

    def ==(other) 
    @board == other.board 
    end 
end 
s = Set.new 
c = C.new 
s.add(c) 
s.include? C# => true 

以下原因將無法正常工作:

s.add(C.new) 
s.include?(C.new) # => false 

使用C.new創建2個不同的對象。如果你運行C.new三次,那麼你將得到3個不同的對象:

C.new.object_id # => 74070710 
C.new.object_id # => 74070360 
C.new.object_id # => 74070030 

摘要:C的情況下,你加入到s,使用Set#add和你正在使用檢查C的實例Set#include?是2不同的對象。所以你得到的結果更加明顯。

+0

我倒下了,因爲這不能回答我的問題。我知道要求包含*相同的對象*將返回true,我關心添加兩個共享相同結構的不同對象。無論如何,正如其他答案所說,關鍵是使用'hash'。 – whatyouhide

+0

@whatyouhide你對我投票對我來說沒有問題..但唯一的問題是你正在犯一些錯誤,以瞭解你的類「C」和類「Set」之間的區別。請遵循[**轉換**](http://chat.stackoverflow.com/rooms/38656/discussion-between-arup-rakshit-and-brabertaser1992),希望您能理解您內心發生了什麼問題。你接受的答案和我一樣。你爲什麼認爲'Set#include?'會比較使用'C#=='方法的對象。爲了清楚起見,檢查'Set#add'和'Set#include?'的實現。 –

+0

我沒有完全理解你的評論,無論如何閱讀Jorg M Mittag的評論:我需要一個集合來考慮具有不同ID但具有與同一對象相同特徵的兩個對象。你告訴我,向一個Set添加兩個不同的對象(具體是不同的ID)導致該設置將它們視爲不同的對象,我已經知道它們。 – whatyouhide

1
class C 
    attr_accessor :board # board is a multidimensional array (represents a matrix) 

    def initialize 
     board = [[1],[2]] # initialize board 
     p @board #=> nil !! 

    end 
    def ==(other) 
     @board == other.board 
    end 

    def eql?(other) # not used 
     puts "eql? called" 
     @board == other.board 
    end 
    def ==(other) # not used 
     puts "== called" 
     @board == other.board 
    end 

    def hash 
     puts "hash called" 
     board.hash 
    end 
end 
require 'set' 
s = Set.new 
s.add(c = C.new) 
p s.include?(c) 

設置使用哈希作爲存儲下方。輸出:

nil 
hash called 
hash called 
true