3

除了红宝石之外,有没有类似 boost::multi_index 的东西。基本上采用一些对象容器,并使用 N 种不同的查询方法对 N 种不同的方法进行索引。

我想您可以将 DataMapper 与内存数据库中的 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  )
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 回答