3

boost::multi_index のようなものはありますが、ルビー用です。基本的に、オブジェクトのコンテナをいくつか取り、N 個の異なるクエリ メソッドを使用して N 個の異なる方法でインデックスを作成します。

SQLite in memory データベースで DataMapper を使用できると思いますが、純粋な Ruby が周りにあるかどうか疑問に思っていました。

以下は、このタイプのクラスが何をするかの想像上の例です。これは、データベースに非常によく似ています。

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  )
4

2 に答える 2

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
于 2010-09-01T08:09:03.987 に答える
-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.
于 2010-09-01T05:40:49.433 に答える