iamse7en iamse7en - 18 days ago 7
Ruby Question

Ruby: Comparing arrays and creating new ones based on specific conditions

I have 3 arrays of equal length. Some spots are nil, which complicates things, but I need to retain their order.

a = [5.2, 3.0, 1.21, 7.0, 5.0, 5.0, 6.0, 8.0, 10.0, 10.0]
b = [nil, nil, [{"price"=>1.99, "size"=>269.897475661239}], nil, nil, nil, nil, nil, nil, nil]
x = [6.0, 6.2, 2.5, 5.0, 9.0, 2.36, 15.5, 20.0, nil, nil]


(Step One, I want to iterate over b so that
b = [nil, nil, 1.99, nil, nil, nil, nil, nil, nil, nil]
. Just need ["price"], ignore ["size"]. Couldn't figure that out.)

Step Two, I want to create a new array (
c
) that averages
a
and
b
but where there is nil, just take the one that has a value. In other words,
c
would
= [5.2, 3.0, 1.6, 7.0, 5.0, 5.0, 6.0, 8.0, 10.0, 10.0]
which looks like
a
except the third spot the average of 1.21 and 1.99 (1.6).

So I have my original third array
x = [6.0, 6.2, 2.5, 5.0, 9.0, 2.36, 15.5, 20.0, nil, nil]
. Step Three, I want to compare
c
and
x
to and create a new array
z
that takes the SMALLER of the two numbers, or if nil, the one that has a value.
z
is the result I would like.

Thus
z
should
= [6.0, 6.2, 2.5, 7.0, 9.0, 5.0, 15.5, 20.0, 10.0, 10.0]
(if my eyes are correct).

I know those steps are tedious, but I need to go in that order because I have lots of arrays where I need to average 2 then compare with a third and take the larger number and with random nil values laced throughout, it gets beyond my abilities. Can't figure it out, and would greatly appreciate some help! Thank you!

Answer
bb = b.map { |e| e.is_a?(Array) ? e.first["price"] : e }
  #=> [nil, nil, 1.99, nil, nil, nil, nil, nil, nil, nil] 

c = a.zip(bb).map { |ea, ebb| ebb.nil? ? ea : (ea+ebb)/2.0 }
  #=> [5.2, 3.0, 1.6, 7.0, 5.0, 5.0, 6.0, 8.0, 10.0, 10.0]

c.zip(x).map { |cc,xx| xx.nil? ? cc : [cc,xx].min }
  #=> [5.2, 3.0, 1.6, 5.0, 5.0, 2.36, 6.0, 8.0, 10.0, 10.0] 

If only the last array is needed, you might first compute bb above, then perform the following calculaton.

[a,bb,x].transpose.map do |ae,bbe,xe|
   ab_avg = bbe ? (ae+bbe)/2.0 : ae
   xe ? [ab_avg, xe].min : ab_avg
end
  #=> [5.2, 3.0, 1.6, 5.0, 5.0, 2.36, 6.0, 8.0, 10.0, 10.0]
Comments