I have an array of arrays being returned from a db and want to make sure they are always the same length. When they are not I want to push zeroes to make them the proper length but also maintain the integrity of the indices.
Most times it will look like
array = [["apple", "blueberries", "banana", "kiwi"], ["20.15", "13.50", "22.10", "10.50"], ["10", "12", "26", "34"]]
I'll eventually be calling each_with_index
and will need them to match up ie. apple,20.15,10 in a table.
Every so often, one or two elements could be missing from an array and I'd like to push zeroes into their place.
array2 = [["apple", "blueberries", "banana", "kiwi"], ["20.15", "22.10"], ["10", "12", "26", "34"]]
I've tried something like
array2.each {|f| f.push(0) until f.length === 4}
=>[["apple", "blueberries", "banana", "kiwi"], ["20.15", "13.50", 0, 0], ["10", "12", "26", "34"]]
but the zeroes are going to be pushed to the end of the array - Ideally the output would be
=>[["apple", "blueberries", "banana", "kiwi"], ["20.15", 0, "13.50", 0], ["10", "12", "26", "34"]]
I hate to break it to you, but programming is not an easy task for kids, as non-programmer adults sometimes imagine. Your case calls for creation of a separate class, perhaps a subclass of Array. Like this:
class GreenGrocer < Array
end
Now we could imagine redefining GreenGrocer.new
public class method to make sure that each GreenGrocer
instance has missing elements patched with zeroes, like this:
class GreenGrocer # reopening the class we defined earlier
class << self
def new array
produce, float_array, int_array = array.reduce( &:zip ).map( &:flatten ).transpose
super [ produce, float_array.map { |e| e or 0.0 }, int_array.map { |e| e or 0 } ]
end
def [] *elements; new elements end
end
end
# so we can call
g = GreenGrocer.new( array2 )
# or
g = GreenGrocer[ *array2 ]
But why bother? It is enough to make a #to_table
method that converts your incomplete data structure to a table as you require, filling the missing data points with zero in the process. So we define:
class LazierGreenGrocer < Array
def to_table
reduce( &:zip ).map( &:flatten ).map { |e| e.map { |e| e || 0 } }
end
end
lazier_g = LazierGreenGrocer.new( array2 ) # not eager to do work upon initialization
lazier_g.to_table # does the required work as #to_table is called
This is how I'd go about it. Since I do not know what exact kind of table do you want to output, you may have to modify my #to_table
method accordingly.