hi all,
ok here's the scoop. i have a collection of hashes all with an arbitrary
number of symbolic keys pointing to arbitrary objects. i have a template
hash also containing symbol keys pointing to 'matching objects', i.e.
objects to be matched with the objects in the aforementioned collection,
and i want to pull out the first match. an example:
# please don't psychoanalyze the below
collection = [
聽聽{ :foo => 'python', :bar => 'php', :x => 69 },
聽聽{ :foo => 'scheme', :mama => 'ruby', :papa => 'C' },
聽聽{ :x => 386 },
聽聽{ :mama => 'ruby', :papa => 'simula', :lil_bro => 'fortran' }
]
template1 = { :mama => 'ruby', :papa => 'C' }
template2 = { :x => Numeric }
match_first(template1, collection)
# should return: { :foo => 'scheme', :mama => 'ruby', :papa => 'C' }
match_all(template2, collection)
# should return: [{:x => 386 }, {:foo => 'python', :bar => 'php', :x =>
69}]
so obviously === is being used internally as is evidenced by Numeric in
template2, but what kind of datastructures/algorithms should i be
looking at for the most efficient (time-wise) implementation, keeping in
mind, there may be many hashes in the collection and those hashes are
generally not very large, i.e. contain few key/value pairs. i'm not too
savy on the taxonomy of algorithms so any pointers to what i should be
looking at to read up on would be appreciated.
my potentially naive solution is something like the following (in full
color http://pastie.caboo.se/130033):
require 'set'
@collection = {}
def add hash
聽聽hash.each do |key,value|
聽聽聽聽(@collection[key] ||= Set.new) << hash
聽聽end
end
def candidates template
聽聽sets = []
聽聽template.keys.each do |key|
聽聽聽聽sets << @collection[key] if @collection.include? key
聽聽end
聽聽if sets.empty?
聽聽聽聽return sets
聽聽else
聽聽聽聽return sets.inject(sets.pop) do |intersection, set|
聽聽聽聽聽聽intersection & set
聽聽聽聽end
聽聽end
end
def match template, hash
聽聽template.each do |key, match|
聽聽聽聽return false unless match === hash[key]
聽聽end
聽聽return true
end
def match_first template
聽聽candidates(template).each do |hash|
聽聽聽聽return hash if match(template, hash)
聽聽end
聽聽return nil
end
def match_all template
聽聽return candidates(template).select do |hash|
聽聽聽聽match(template, hash)
聽聽end
end
[
聽聽{ :foo => 'python', :bar => 'php', :x => 69 },
聽聽{ :foo => 'scheme', :mama => 'ruby', :papa => 'C' },
聽聽{ :x => 386, :papa => 'clause' },
聽聽{ :mama => 'ruby', :papa => 'simula', :lil_bro => 'fortran' },
聽聽{ :mama => 1946, :boo => 'far', :x => 'x'}
].each do |hash|
聽聽add hash
end
puts match_first({ :mama => 'ruby', :papa => 'C' }).inspect
puts match_all({:foo => String}).inspect
thanks for reading this far!
_c
路路路
--
Posted via http://www.ruby-forum.com/.