1

I have a three lines of code here like shown below

local = headers.zip(*data_rows).transpose
local = local[1..-1].map {|dataRow| local[0].zip(dataRow).to_h}
p local

Now if you watch the above three lines, I have to store the result of the first line in the variable called local since it would be used in two places in the second line as I have shown,So Can't I cascade the second line with first line anyway? I tried using tap like this

local = headers.zip(*data_rows).transpose.tap{|h|h[1..-1].map {|dataRow| h[0].zip(dataRow).to_h}}

tap is returning the self as explained in the document so can't I get the result final result when I use tab? Anyway other way to achieve this result in one single line so that I don't have to use local variable?

Rajagopalan
  • 5,465
  • 2
  • 11
  • 29

2 Answers2

4

If you're on Ruby 2.5.0 or later, you can use yield_self for this.

local = headers.zip(*data_rows).transpose.yield_self { |h| h[1..-1].map { |dataRow| h[0].zip(dataRow).to_h } }

yield_self is similar to tap in that they both yield self to the block. The difference is in what is returned by each of the two methods.

Object#tap yields self to the block and then returns self. Kernel#yield_self yields self to the block and then returns the result of the block.

Here's an answer to a previous question where I gave a couple of further examples of where each of these method can be useful.

mikej
  • 65,295
  • 17
  • 152
  • 131
2

It's often helpful to execute working code with data, to better understand what is to be computed. Seeing transpose and zip, which are often interchangeable, used together, was a clue that a simplification might be possible (a = [1,2,3]; b = [4,5,6]; a.zip(b) => [[1, 4], [2, 5], [3, 6]] <= [a,b].transpose).

Here's my data:

headers=[1,2,3]
data_rows=[[11,12,13],[21,22,23],[31,32,33],[41,42,43]]

and here's what the working code returns:

local = headers.zip(*data_rows).transpose
local[1..-1].map {|dataRow| local[0].zip(dataRow).to_h}
  #=> [{1=>11, 2=>12, 3=>13}, {1=>21, 2=>22, 3=>23},
  #    {1=>31, 2=>32, 3=>33}, {1=>41, 2=>42, 3=>43}]

It would seem that this might be computed more simply:

data_rows.map { |row| headers.zip(row).to_h }
  #=> [{1=>11, 2=>12, 3=>13}, {1=>21, 2=>22, 3=>23},
  #    {1=>31, 2=>32, 3=>33}, {1=>41, 2=>42, 3=>43}]
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100