红宝石的多指数容器

时间:2010-08-31 19:43:21

标签: ruby boost multi-index

有什么像boost :: multi_index但是对于ruby。基本上采取一些 对象的容器,并使用N种不同的查询方法将其编入N个不同的方式。

我猜你可以在内存数据库中使用Dataiteper和SQLite,但我确实如此 想知道周围是否有纯红宝石。

以下是这类课程可能做的想象的例子。它看起来非常 很像数据库。

class Foo
    attr_accessor :a
    attr_accessor :b
    attr_accessor :c
end


class FooIndexer < MultiIndex
    hash_index :a do |o|
        o.a
    end

    ordered_index :b do |x, y|
        x.b <=> y.b
    end
end


index = FooIndexer.new

index.insert( Foo.new ( ... ))
index.insert( Foo.new ( ... ))
index.insert( Foo.new ( ... ))
index.insert( Foo.new ( ... ))
index.insert( Foo.new ( ... ))


index.find ( index.a == 10 )
index.find ( index.b > 10  )

2 个答案:

答案 0 :(得分:1)

这是一个完整的解决方案,包括规范,但仅适用于 多个哈希键。

require 'pp'

class MKey
  def initialize &bk
    @block = bk
    @containers = {}
  end

  def <<(val)
    keys = @block.call(val)
    keys.each do |k,v|
      @containers[k] ||= {}
      @containers[k][v] = val
    end
  end

  def [](key)
    k, v = key.first
    @containers[k][v]
  end

  def delete(key)
    val = self[key]
    keys = @block.call(val)
    keys.each do |k,v|
      @containers[k].delete(v)
    end
  end

  include Enumerable

  def each
    k, c = @containers.first 
    c.each do |k, val|
      yield val
    end
  end

end


describe MKey do 

  class Foo
    def initialize(a,b)
      @a = a
      @b = b
    end
    attr_accessor :a
    attr_accessor :b
  end

  it "should insert" do

    index = MKey.new do |o|
      { :a => o.a,
        :b => o.b
      }
    end

    x = Foo.new("hello", "cat")
    y = Foo.new("goodbye", "code")

    index << x
    index << y

    # Test Enumerable interface
    index.find do |val|
      val.a == "hello"
    end.should == x

    # Test multi key interface
    index[:a => "hello"].should == x
    index[:b => "code"].should == y

    index.delete(:a => "hello")

    index[:a => "hello"].should == nil
    index[:b => "code"].should == y

    index.delete(:b => "code")

    index[:a => "hello"].should == nil
    index[:b => "code"].should == nil


  end

  it "hash lookup should be faster than find" do


    index = MKey.new do |o|
      { :a => o.a,
        :b => o.b
      }
    end

    for i in 1..10000
      index << Foo.new(i, i*100)
    end

    t0 = timer do
      index[:a => 1000]
    end

    t1 = timer do
      index.find {|v| v.a == 10000}
    end

    t0.should < t1 * 100 

  end

end

答案 1 :(得分:-1)

听起来你是在追求实现此功能的特定方式。但就类似ruby的接口而言,我建议只使用Enumerable#find方法。这样,你可以说

foo_container = [FooIndexer.new, ...]
foo_container.find{|x| x.a == 10}

看起来非常像你的例子,除了括号而不是括号!

稍后,如果您发现性能非常差,则可能需要某种缓存或优化find。但是,仅基于您的问题,如果您现在寻找,那么您将很快进行优化。

Enumerable已经提供了很多这样的东西,所以你有自然的扩展,比如

foo_container.select{|x| x.a == 10}  # Finds all instances.
foo_container.reject{|x| x.a == 10}  # Finds the complementary set.