I'm looking for a more elegant way of blending together two SQL resultsets with a given ratio. Within each of them I want them to be worked through in the same order they come in, but I want to interleave the processing to achieve a desired blend.
I realised this can be made into a very generic method working with two enums and yielding items to process, so I've written this method which I'm simultaneously quite proud of (nice generic solution) and quite ashamed of.
def combine_enums_with_ratio(enum_a, enum_b, desired_ratio)
a_count = 1
b_count = 1
a_finished = false
b_finished = false
loop do
ratio_so_far = a_count / b_count.to_f
if !a_finished && (b_finished || ratio_so_far <= desired_ratio)
begin
yield enum_a.next
a_count += 1
rescue StopIteration
a_finished = true
end
end
if !b_finished && (a_finished || ratio_so_far > desired_ratio)
begin
yield enum_b.next
b_count += 1
rescue StopIteration
b_finished = true
end
end
break if a_finished && b_finished
end
end
Ashamed because it's clearly written in a very imperative style. Not looking very rubyish. Maybe there's a way of using one of ruby's nice declarative looping methods, except they don't seem to work holding open two enums like this. So then I believe I'm left having to rescue an exception as part of control flow like this, which feels very dirty. I'm missing java's hasNext()
method.
Is there a better way?
I did find a similar question about comparing enums: Ruby - Compare two Enumerators elegantly . Some compact answers, but not particularly solving it, and my problem involving unequal lengths and unequal yielding seems trickier.