Best way to fill in spaces in a multidimensional array in Ruby

I have a multidimensional array similar to the example below, which I want to group using the Ruby zip method. I work fine when each inner array has the same number of elements, but I run into problems when they are different.

In the example below, in the second set there is no entry at 00:15. How to fill in this missing entry?

What do I consider as a space?

This is a timestamp that represents a gap. Take a look at my first sample code, where I have a comment about the gap is 00:15. All other arrays have a hash with this timestamp, so I consider this to be a “missing entry” or a “space”. timestamp can really be some other unique string, so the fact that they are 15 minutes apart doesn't matter. Values ​​also do not matter.

The only approach that comes to mind is to iterate over arrays twice. The first time it would be necessary to build an array of uniq timestamps, and the second time - to fill in the missing record (s), where there is no timestamp. I find it more convenient to code this approach, but it seems a bit hacky, and Ruby always surprises me with an elegant and concise solution.

I'll start with this:

values = [
  [
    {:timestamp => "2011-01-01 00:00", :value => 1},
    {:timestamp => "2011-01-01 00:15", :value => 2},
    {:timestamp => "2011-01-01 00:30", :value => 3}
  ],
  [ # There a gap here at 00:15
    {:timestamp => "2011-01-01 00:00", :value => 1},
    {:timestamp => "2011-01-01 00:30", :value => 3}
  ],
  [
    {:timestamp => "2011-01-01 00:00", :value => 1},
    {:timestamp => "2011-01-01 00:15", :value => 2},
    {:timestamp => "2011-01-01 00:30", :value => 3}
  ]
]

I want to end with this:

values = [
  [
    {:timestamp => "2011-01-01 00:00", :value => 1},
    {:timestamp => "2011-01-01 00:15", :value => 2},
    {:timestamp => "2011-01-01 00:30", :value => 3}
  ],
  [ # The gap has been filled with a nil value
    {:timestamp => "2011-01-01 00:00", :value => 1},
    {:timestamp => "2011-01-01 00:15", :value => nil},
    {:timestamp => "2011-01-01 00:30", :value => 3}
  ],
  [
    {:timestamp => "2011-01-01 00:00", :value => 1},
    {:timestamp => "2011-01-01 00:15", :value => 2},
    {:timestamp => "2011-01-01 00:30", :value => 3}
  ]
]

, values.transpose :

[
  [
   {:value=>1, :timestamp=>"2011-01-01 00:00"}, 
   {:value=>1, :timestamp=>"2011-01-01 00:00"}, 
   {:value=>1, :timestamp=>"2011-01-01 00:00"}
  ], 
  [
    {:value=>2, :timestamp=>"2011-01-01 00:15"}, 
    {:value=>nil, :timestamp=>"2011-01-01 00:15"},
    {:value=>2, :timestamp=>"2011-01-01 00:15"}
  ], 
  [
    {:value=>3, :timestamp=>"2011-01-01 00:30"}, 
    {:value=>3, :timestamp=>"2011-01-01 00:30"}, 
    {:value=>3, :timestamp=>"2011-01-01 00:30"}
  ]
]
+3
3

, , , , , . , :

stamps = values.map{ |logs| logs.map{ |row| row[:timestamp] } }.flatten.uniq.sort
values.map!{ |logs| stamps.map { |ts| logs.select{ |row| row[:timestamp] == ts }.first || { :timestamp => ts, :value => nil } } }

( , , ).

( , , - , ).

+1

; , . . , Ruby 1.9.2:

values = [[
  {:timestamp => "2011-01-01 00:00", :value => 1},
  {:timestamp => "2011-01-01 00:15", :value => 2},
  {:timestamp => "2011-01-01 00:30", :value => 3}
],[
  {:timestamp => "2011-01-01 00:00", :value => 1},
  {:timestamp => "2011-01-01 00:30", :value => 3}
],[
  {:timestamp => "2011-01-01 00:00", :value => 1},
  {:timestamp => "2011-01-01 00:15", :value => 2},
  {:timestamp => "2011-01-01 00:30", :value => 3}
]]

all_stamps = values.flatten.map{|x| x[:timestamp]}.uniq.sort
values.each do |set|
  my_stamps = set.map{ |x| x[:timestamp] }.uniq
  missing   = all_stamps - my_stamps
  set.concat( missing.map{ |stamp| {timestamp:stamp, value:nil} } )
  set.replace( set.sort_by{ |x| x[:timestamp] } )
end

require 'pp'
pp values
#=> [[{:timestamp=>"2011-01-01 00:00", :value=>1},
#=>   {:timestamp=>"2011-01-01 00:15", :value=>2},
#=>   {:timestamp=>"2011-01-01 00:30", :value=>3}],
#=>  [{:timestamp=>"2011-01-01 00:00", :value=>1},
#=>   {:timestamp=>"2011-01-01 00:15", :value=>nil},
#=>   {:timestamp=>"2011-01-01 00:30", :value=>3}],
#=>  [{:timestamp=>"2011-01-01 00:00", :value=>1},
#=>   {:timestamp=>"2011-01-01 00:15", :value=>2},
#=>   {:timestamp=>"2011-01-01 00:30", :value=>3}]]

Ruby 1.9.2 set.replace( set.sort_by{...} ) set.sort_by!{ ... }. , , Ruby 1.9 - (. missing.map...).

+1

Also check Array#in_groups_ofif you are using Rails

%w(1 2 3 4 5 6 7).in_groups_of(3) {|g| p g}
["1", "2", "3"]
["4", "5", "6"]
["7", nil, nil]

http://weblog.rubyonrails.org/2006/3/1/new-in-rails-enumerable-group_by-and-array-in_groups_of

0
source

Source: https://habr.com/ru/post/1787821/


All Articles