Patosai
Patosai

Reputation: 760

Zip array of arrays to another array

Let's say I have an array

arr1 = ["a", "b", "c"]

and I want to zip an array of arrays to it

arr2 = [[1, "foo"], [2, "bar"], [3, "baz"]]

so that the end result is

[["a", 1, "foo"], ["b", 2, "bar"], ["c", 3, "baz"]]

Right now what I'm doing is arr1.zip(arr2).map!(&:flatten), but I'm wondering if there's a better way to do this?

Upvotes: 6

Views: 718

Answers (4)

Ulysse BN
Ulysse BN

Reputation: 11403

If you need the content of arr2 to be before the content of arr1, you cannot use the #transpose trick. However, you can:

arr1.map.with_index { |el, i| [*arr2[i], el] }
# => [[1, "foo", "a"], [2, "bar", "b"], [3, "baz", "c"]]

Which has the perks of:

  1. not mutating original arrays
  2. let you choose the order

In terms of performance, Doguita's answer seems better:

arr1 = %w(foo) * 10_000
arr2 = arr1.length.times.map { |i| [i, i.to_s(2)] }
Benchmark.bmbm(20) do |x|
  x.report("zip & transpose:") { arr1.zip(*arr2.transpose) }
  x.report("map & with_index:") { arr1.map.with_index { |v, i| [v, *arr2[i]] } }
end
Rehearsal --------------------------------------------------------
zip & transpose:       0.000902   0.000233   0.001135 (  0.001107)
map & with_index:      0.004206   0.002308   0.006514 (  0.006828)
----------------------------------------------- total: 0.007649sec

                           user     system      total        real
zip & transpose:       0.001474   0.000045   0.001519 (  0.001471)
map & with_index:      0.002155   0.000059   0.002214 (  0.002282)

Upvotes: 1

Cary Swoveland
Cary Swoveland

Reputation: 110725

Here are two other (closely-related) ways:

enum = arr1.to_enum
arr2.map { |a| [enum.next].concat(a) }
  #=> [["a", 1, "foo"], ["b", 2, "bar"], ["c", 3, "baz"]] 

or

arr1_cpy = arr1.dup
arr2.map { |a| [arr1_cpy.shift].concat(a) }
  #=> [["a", 1, "foo"], ["b", 2, "bar"], ["c", 3, "baz"]] 

Upvotes: 3

aaron-coding
aaron-coding

Reputation: 2621

arr2.each_with_index{ |el,i| el.unshift(arr1[i]) }

Maybe you like that better?

Upvotes: 1

Doguita
Doguita

Reputation: 15723

Another way is:

arr1.zip(*arr2.transpose)
# => [["a", 1, "foo"], ["b", 2, "bar"], ["c", 3, "baz"]]

Upvotes: 13

Related Questions