在Ruby中的无序夫妇

时间:2009-09-01 11:59:22

标签: ruby

我想计算用户之间的相似性,这是互惠的。

similarity[:user1][:user2] == similarity[:user2][:user1]

所以使用它会很棒:

unordered_set(:user1, :user2) = 1
unordered_set(:user2, :user1) += 1

read_unordered_set(:user1, :user2) #=> 2
read_unordered_set(:user2, :user1) #=> 2

如何在Ruby中获得类似的行为?

2 个答案:

答案 0 :(得分:6)

http://www.ruby-doc.org/core/classes/Set.html

[1, 2].to_set == [2, 1].to_set

可能有帮助......

答案 1 :(得分:1)

这里缺少的部分是< =>符号上的运算符。如果您定义一个,那么解决方案将是:

# We define our own <=> operation on symbols
Symbol.class_eval do
  def <=>(other)
    self.to_s <=> other.to_s
  end
end


# Our set
class UnorderedSet
  def initialize
    @hash = Hash.new
  end

  def [](k1, k2)
    @hash[[k1, k2].sort]
  end

  def []=(k1, k2, value)
    @hash[[k1, k2].sort] = value
  end

  def keys
    @hash.keys
  end

  def values
    @hash.values
  end

  def each
    @hash.each do |k, v|
      yield(k, v)
    end
  end
  include Enumerable
end

当然,我们为该容器提供了一些测试:

if __FILE__ == $0
  require 'test/unit'

  class UnorderedSetTest < Test::Unit::TestCase
    def setup
      @set = UnorderedSet.new
    end

    def test_bracket_operators
      assert_equal(nil, @set[:unknown, :key])

      @set[:user1, :user2] = 1
      @set[:user2, :user1] += 1

      assert_equal(2, @set[:user1, :user2])
      assert_equal(2, @set[:user2, :user1])
    end

    def test_enumerability
      h = {
        [:user1, :user2] => "ruby",
        [:c, :d] => "is",
        [:b, :a] => "easy",
        [:f, :e] => "!"
      }

      h.each do |k, v|
        @set[*k] = v
      end

      assert_equal(h.values.sort, @set.values.sort)
      assert_equal(h.keys.collect { |k| k.sort }.sort, @set.keys.sort)
      assert_equal(h.to_a.collect { |k, v| [k.sort, v] }.sort, @set.to_a.sort)
    end
  end
end

此代码已使用ruby 1.8.2进行测试。当然,不要期待太多表现......