tags:

views:

236

answers:

4

i have 4 arrays.

["one", "two", "three"]
["1", "2", "3"
["un", "deux", "trois"]
["ichi", "ni", "san"]

is it possible to concatenate each element in their respective arrays ?

so i end up with single lines of string like like

"one, 1, un, ichi"\n
"two,2, deux,ni"\n

and so on...

is it possible to do this in one loop ?

for i in (1..array1.count)

puts array1[i] + ", " + array2[i] + ", " + array3[i] + ", " + array4[i]

end

What happens when there might be unpredictable number of arrays & they are each unequal size?

A: 

Well if you know that they were all the same length:

(0...array1.length).each{|i|puts array1[i] + ", " + array2[i] + ", " + array3[i] + ", " + array4[i]}

Edit: The Following code works

array1 = ["one", "two", "three"]
array2 = ["1", "2", "3"]
array3 = ["un", "deux", "trois"]
array4 = ["ichi", "ni", "san"]

(0...array1.length).each{|i| puts array1[i] + ", " + array2[i] + ", " + array3[i] + ", " + array4[i]}

Edit2: what happens if you dont know how many arrays there will be?

I would suggest making an array of arrays; a list of arrays. Make an array of arrays (essentially a 2D array but it can't be indexed like one) and with it print every line one by one for each array in the arrayList.

This code works:

array1 = ["one", "two", "three"]
array2 = ["1", "2", "3"]
array3 = ["un", "deux", "trois"]
array4 = ["ichi", "ni", "san"]

arrayList = []
arrayList.push(array1, array2, array3, array4)

p arrayList

(0...array1.length).each{|i|
    (0...arrayList.length).each{|j|
        print arrayList[j][i] + ", "
    }
    print "\n"
}
Robert Massaioli
what happens if you dont know how many array there really is ?
gqweg
Your second method will print out too many `", "` strings.
Chris Lutz
Yes it does, i mentioned that in my comment above, using join is nicer.
Robert Massaioli
yeah seems like no other short cut way to do this. i have a similar setup as this.
gqweg
I don't really think this is the best way. There are ways to make the `zip` and `transpose` solutions work for you. It may take a little extra effort, but IMHO the code ends up a little cleaner looking.
Chris Lutz
See the second method I just added to my answer...
glenn mcdonald
+1  A: 

I would use Enumerable#zip to create an array of arrays. It will create an array where the first element is an array of the first elements of all the arrays you pass to it, and so on with the second, third, etc. Then go through this list and print each argument using Array#join. Something like:

a.zip(b, c, d).each do |l|
  puts l.join(", ")
end

EDIT: No, zip won't be very helpful as far as appending arrays goes. glenn's method is good for that. You can append to the end of a zipped array, but it's not as easy:

e = a.zip(b, c)
e.length.times { |i| e[i].push(d[i]) }
Chris Lutz
what if you dont know how many arrays you are dealing with. can you "push" arrays to a .zip() in a loop ?
gqweg
Disregard that first edit. My brain was not working properly.
Chris Lutz
+3  A: 

Easy:

a = [array1,array2,array3,array4] # or however many you have

puts a.transpose.map {|x| x.join(", ")}.join("\n")

This will work with any number of subarrays as long as they are all the same size (regardless of what that size is).

If the subarrays are different lengths, but it's OK to use the length of the first one, you can do this:

a[0].zip(*a[1..-1]).map {|x| x.join(", ")}.join("\n")
glenn mcdonald
That's a nice solution. I like my `zip` solution more (because it's mine, and because it puts them in the right order the first time), but it's nice to know about `transpose`.
Chris Lutz
Zip is great for pairs of arrays. But it only works if you know at code-writing time how many arrays you have, whereas transpose takes the array of arrays whole, and thus doesn't care how big it is. The transpose way is slightly faster, too.
glenn mcdonald
is it possible to make it still work even when array's are not all same size?
gqweg
We can make them all the same length: `n = a.map { |i| i.length }.max; n.times { |i| a[i].concat([nil] * (n - a[i].length)) }` (this pads them all with `nil` values so we can safely transpose them).
Chris Lutz
In my sleep I realized how to make the zip version work on any number of arrays: the mighty *.
glenn mcdonald
A: 

If you are using ruby 1.9 maybe you can take advantage of external iterators, this will let you deal with any number of arrays:

array1 = ['one','two','three']
array2 = [1,2,3,4]
array3 = ['un','deux','trois']
array4 = ['ichi','ni','san']

def bundle(*enumerables)
  enumerators = enumerables.map{ |e| e.to_enum }
  loop { puts enumerators.map { |e| e.next }.join(', ') }
end

bundle(array1,array2,array3,array4)

produces:

one, 1, un, ichi
two, 2, deux, ni
three, 3, trois, san
Miguel Fonseca