有什么像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 )
答案 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.