tags:

views:

88

answers:

3

I have two arrays:

x = [ ["0", "#0"], ["1", "#1"] ]
y = [ ["00", "00 description"], ["10", "10 description"] ]

What i need is to merge them so i get the following as result:

result = [ ["000", "#0 00 description"], ["010", "#0 10 description"],
   ["100", "#1 00 description"], ["110", "#1 10 description"] ]

Is there a method for that? Or I'll need to use collect or something like this?

Thanks in advance.

+2  A: 

In your example you seem to be applying special rules for concatenating the digits of specific decimal representations of integers, which doesn't work in any simple manner (e.g. when you write 00 it's just 0 to the interpreter). However, assuming simple string concatenation is what you meant:

x = [ ["0", "#0"], ["1", "#1"] ]
y = [ ["00", "00 description"], ["10", "10 description"] ]
z = []
x.each do |a|
  y.each do |b|
    c = []
    a.each_index { |i| c[i] = a[i] + b[i] }
    z << c
  end
end
p z

Edit: The originally posted version of the question had integers as the first elements of each sub-array, the preface to the solution refers to that. The question has since been edited to have strings as assumed here.

Arkku
Of course you can replace the `a.each_index` loop with something more specific to your application, e.g. `c[0] = a[0] * 100 + b[0]`.
Arkku
+1. yes, can be string concatenation. but i was looking for the prettier way to do that... and this doesn't look pretty. tks anyway.
j.
Dude. This is a 7 line solution. Even if you find a one liner, it's almost definitely not going to be as clean and understandable as this one. Why does it have to be "pretty"? It fits on your screen and does the job, that's all that should matter.
ryeguy
@ryeguy, Mladen Jablanović's solution is absolutely understandable and, in my opinion, pretty. The answer does not `have` to be pretty, but I wanted it to be :]
j.
Agree that using `product` is prettier than doing it manually as here. Apparently it requires quite a recent version of Ruby, however, as mine didn't have it. Meanwhile the solutions with `inject` and `zip` seem less obvious to me, but of course it's a matter of what one is used to.
Arkku
I have updated my answer with product-free solution. Agree on subjectivity of which one is readable, some prefer more imperative style, others more functional.
Mladen Jablanović
+1  A: 

You can use Array#product method:

x = [ ['0', "#0"], ['1', "#1"] ]
#=> [["0", "#0"], ["1", "#1"]]
y = [ ['00', "00 description"], ['10', "10 description"] ]
#=> [["00", "00 description"], ["10", "10 description"]]
x.product(y).map{|a1,a2| [a1[0]+a2[0], a1[1] + ' ' + a2[1]]}
#=> [["000", "#0 00 description"], ["010", "#0 10 description"], ["100", "#1 00 description"], ["110", "#1 10 description"]]

And if you wouldn't need different kinds of concatenation above (second one is inserting space between), even:

x.product(y).map{|a1,a2|
  a1.zip(a2).map{|e|
    e.inject(&:+)
  }
}

And here's a variant without Array#product, admittedly less readable:

x.inject([]){|a,xe|
  a + y.map{|ye|
    xe.zip(ye).map{|e|
      e.inject(&:+)
    }
  }
}
Mladen Jablanović
Almost identical!
glenn mcdonald
perfect. thank you!
j.
@glenn: yup... :) I didn't think of `join`, but then again, I had numbers in mind as well as strings, according to the original version of the question.
Mladen Jablanović
+1  A: 

In your example you're concatenating the first elements without spaces, but the second elements with spaces. If you can do them both the same way, this can be just:

x.product(y).map {|a,b| a.zip(b).map(&:join)}
=> [["000", "#000 description"], ["010", "#010 description"], ["100", "#100 description"], ["110", "#110 description"]]

If the different concatenations are required, this'll do:

x.product(y).map {|a,b| [a[0]+b[0],a[1]+' '+b[1]]}
=> [["000", "#0 00 description"], ["010", "#0 10 description"], ["100", "#1 00 description"], ["110", "#1 10 description"]]
glenn mcdonald
Looks like it's time for me to update my Ruby installation; don't have `product` in mine. =)
Arkku
@Arkku, If you can't upgrade to 1.9, you will be pleased to know that `product` has been backported to 1.8.7. And if you can't upgrade to 1.8.7, the "backports" gem ought to have it.
Wayne Conrad