I have an array ‘conds’, which contains some sub-expressions for an
xpath query:
conds = [“@title=‘Foo’”, “@edition=‘Bar’”, “@date=‘20040513’”]
Something i made some weeks ago seems related to this. In my case, i
wanted to generate a number of combinations by assigning a set of
possible values to a number of ‘fields’ (you also seem to have fields
and values you want to assign to them). I don’t know whether this is
relevant to you, but it might give you some ideas…
So, the first thing i had, was a class ‘Profile’ which is merely a
placeholder for the ‘fields’. The constructor of ‘Profile’ takes a
Hash as parameter. This Hash is used to assign a certain value to
certain fields (the fields are just instance variables), fields not
included as key in the Hash recieve a default value.
I needed to build a lot of these Profiles and my idea was to define a
number of ‘constraints’ on certain fields, like this:
constraints = {“size” => [22,23,24,25],
“tidy” => [true,false],
“new” => [true],
“freq” => [[2,2],[2,4],[2,8]] }
With those constraints, i want to generate Profiles initialized with
the following Hashes:
{“size” => 22, “tidy” => true, “new” => true, “freq” => [2,2]}
{“size” => 22, “tidy” => true, “new” => true, “freq” => [2,4]}
{“size” => 22, “tidy” => true, “new” => true, “freq” => [2,8]}
{“size” => 22, “tidy” => false, “new” => true, “freq” => [2,2]}
{“size” => 22, “tidy” => false, “new” => true, “freq” => [2,4]}
{“size” => 22, “tidy” => false, “new” => true, “freq” => [2,8]}
{“size” => 23, “tidy” => true, “new” => true, “freq” => [2,2]}
{“size” => 23, “tidy” => true, “new” => true, “freq” => [2,4]}
{“size” => 23, “tidy” => true, “new” => true, “freq” => [2,8]}
{“size” => 23, “tidy” => false, “new” => true, “freq” => [2,2]}
{“size” => 23, “tidy” => false, “new” => true, “freq” => [2,4]}
{“size” => 23, “tidy” => false, “new” => true, “freq” => [2,8]}
…
To do this, i made the following ‘GeneratingHash’. You construct it
with a constraints-Hash, and then you can use it as an iterator with
the ‘each’ method. You could use the same idea to generate
combinations of Arrays. A good thing about this way of working is that
you can use it to generate one Hash at a time, do stuff, forget about
the first Hash, generate the next one, do stuff,… might be important
for memory usage in case you have lots of combinations. (and yeah, i
know, it is recursive and will already create x Hashes with ‘x’ the
number of keys you use…)
class GeneratingHash
attr_accessor :constraints
def initialize(constraints)
@constraints = constraints
end
def recursive_each(keys,hash,&block)
if keys.empty?
yield hash
else
key = keys.pop
@constraints[key].each { |val|
my_hash = hash.clone
my_hash[key]=val
my_keys = keys.clone
recursive_each(my_keys,my_hash,&block)
}
end
end
def each(&block)
mykeys = @constraints.keys
recursive_each(mykeys,Hash.new(),&block)
end
end
For those who are interested, i also included the rest of the
(relevant) code. (this is used in a program to perform a number of
benchmarks based on a lot of different ‘setups’(Profiles))
Comments on the code are welcome
Ruben
···
==============================
class Profile
attr_accessor :size, :tidy, :new, :lo_freq, :hi_freq
def initialize(values)
@size = 22 unless @size = values[“size”]
@tidy = false unless @tidy = values[“tidy”]
@new = false unless @new = values[“new”]
if values[“freq”]
@lo_freq = values[“freq”][0]
@hi_freq = values[“freq”][1]
else
@lo_freq = @hi_freq = 0
end
end
…
end
class ProfileCollection
attr_accessor :constraints
def initialize(constraints)
@constraints = constraints
end
def each(&block)
gh = GeneratingHash.new(@constraints)
gh.each { |hash|
prof = Profile.new(hash)
yield prof
}
end
end
=========================================
and those classes are used like this:
constraints = {“size” => [22,23,24,25],
“tidy” => [true,false],
“new” => [true],
“freq” => [[2,2],[2,4],[2,8]] }
prof_collection = ProfileCollection.new(constraints)
prof_collection.each { |profile|
do stuff with the profile
}