Fill gaps in Array of Hashes

I have the following object as a result from MySQL:

[{:positive=>"0", :neutral=>"2", :total=>"5", :date=>"2009-12-01",
:negative=>"3"}, {:positive=>"3", :neutral=>"3", :total=>"7",
:date=>"2009-12-08", :negative=>"1"}, {:positive=>"1", :neutral=>"1",
:total=>"3", :date=>"2009-12-09", :negative=>"1"}]

I want to fill gaps (for example from 2009-11-19 till 2010-10-01) with
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>"HEREDATE",
:negative=>"1" - how i can do this in ruby? In MySQL it's impossible to
do :-(.

···

--
Posted via http://www.ruby-forum.com/.

Joao Silva wrote:

I have the following object as a result from MySQL:

[{:positive=>"0", :neutral=>"2", :total=>"5", :date=>"2009-12-01",
:negative=>"3"}, {:positive=>"3", :neutral=>"3", :total=>"7",
:date=>"2009-12-08", :negative=>"1"}, {:positive=>"1", :neutral=>"1",
:total=>"3", :date=>"2009-12-09", :negative=>"1"}]

I want to fill gaps (for example from 2009-11-19 till 2010-10-01) with
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>"HEREDATE",
:negative=>"1" - how i can do this in ruby? In MySQL it's impossible to
do :-(.

Well, the dumb, brute-force way to do it would be something like this, I
guess:

# Assuming your array is called 'array'
require 'rubygems'
require 'activesupport' # What? I'm lazy. to_date is damn handy.

("2009-11-19".to_date.."2010-10-01".to_date).each do |date|
  exists = array.find { |x| x[:date] == date.to_s }
  next if exists # If the date is found in the array, next date please.
  array << { :positive => "0", :neutral => "0", :total => "0", :date =>
date,
             :negative => "1" }
end

Do you understand this code?

···

--
Posted via http://www.ruby-forum.com/\.

Joao Silva wrote:

I have the following object as a result from MySQL:

[{:positive=>"0", :neutral=>"2", :total=>"5", :date=>"2009-12-01",
:negative=>"3"}, {:positive=>"3", :neutral=>"3", :total=>"7",
:date=>"2009-12-08", :negative=>"1"}, {:positive=>"1", :neutral=>"1",
:total=>"3", :date=>"2009-12-09", :negative=>"1"}]

I want to fill gaps (for example from 2009-11-19 till 2010-10-01) with
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>"HEREDATE",
:negative=>"1" - how i can do this in ruby? In MySQL it's impossible to
do :-(.

Alright... Now that I've helped you do what you asked for, please tell
us what you actually want to do, because actually filling up a hash with
default data is really not optimal.

···

--
Posted via http://www.ruby-forum.com/\.

Yep, i understand, but it returns wrong value (and not sorted by date
;-():

    ("2009-11-11".to_date.."2010-01-01".to_date).each do |date|
      exists = result.find { |x| x[:date] == date.to_s }
      next if exists
      result << { :positive => "0", :neutral => "0", :total => "0",
:date => date, :negative => "0" }
    end

    return result

=> [{:positive=>"0", :neutral=>"2", :total=>"5", :date=>"2009-12-01",
:negative=>"3"}, {:positive=>"3", :neutral=>"3", :total=>"7",
:date=>"2009-12-08", :negative=>"1"}, {:positive=>"1", :neutral=>"1",
:total=>"3", :date=>"2009-12-09", :negative=>"1"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Wed, 11 Nov 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Thu, 12 Nov 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Fri, 13 Nov 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Sat, 14 Nov 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Sun, 15 Nov 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Mon, 16 Nov 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Tue, 17 Nov 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Wed, 18 Nov 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Thu, 19 Nov 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Fri, 20 Nov 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Sat, 21 Nov 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Sun, 22 Nov 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Mon, 23 Nov 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Tue, 24 Nov 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Wed, 25 Nov 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Thu, 26 Nov 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Fri, 27 Nov 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Sat, 28 Nov 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Sun, 29 Nov 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Mon, 30 Nov 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Tue, 01 Dec 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Wed, 02 Dec 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Thu, 03 Dec 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Fri, 04 Dec 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Sat, 05 Dec 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Sun, 06 Dec 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Mon, 07 Dec 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Tue, 08 Dec 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Wed, 09 Dec 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Thu, 10 Dec 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Fri, 11 Dec 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Sat, 12 Dec 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Sun, 13 Dec 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Mon, 14 Dec 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Tue, 15 Dec 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Wed, 16 Dec 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Thu, 17 Dec 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Fri, 18 Dec 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Sat, 19 Dec 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Sun, 20 Dec 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Mon, 21 Dec 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Tue, 22 Dec 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Wed, 23 Dec 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Thu, 24 Dec 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Fri, 25 Dec 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Sat, 26 Dec 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Sun, 27 Dec 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Mon, 28 Dec 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Tue, 29 Dec 2009, :negative=>"0"},
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>Wed, 30 Dec 2009,
:negative=>"0"}, {:positive=>"0", :neutral=>"0", :total=>"0",
:date=>Thu, 31 Dec 2009, :negative=>"0"}, {:positive=>"0",
:neutral=>"0", :total=>"0", :date=>Fri, 01 Jan 2010, :negative=>"0"}]

···

--
Posted via http://www.ruby-forum.com/.

Here's a different approach - not with dates though.

# just an example
def next_val(x)
  x + 2
end

with_gaps = Array.new(10) { rand(40) * 2 }

puts "before"
p with_gaps

with_gaps.sort.each_cons 2 do |a,b|
  next if a == b
  x = a

  while (x = next_val(x)) != b
    with_gaps << x
  end
end

puts "after"
p with_gaps.sort

# automated check
with_gaps.sort.each_cons 2 do |a,b|
  raise("Wrong distance %s" % [a,b].inspect) unless a == b || next_val(a) == b
end

Cheers

robert

···

2009/12/10 Aldric Giacomoni <aldric@trevoke.net>:

Joao Silva wrote:

I have the following object as a result from MySQL:

[{:positive=>"0", :neutral=>"2", :total=>"5", :date=>"2009-12-01",
:negative=>"3"}, {:positive=>"3", :neutral=>"3", :total=>"7",
:date=>"2009-12-08", :negative=>"1"}, {:positive=>"1", :neutral=>"1",
:total=>"3", :date=>"2009-12-09", :negative=>"1"}]

I want to fill gaps (for example from 2009-11-19 till 2010-10-01) with
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>"HEREDATE",
:negative=>"1" - how i can do this in ruby? In MySQL it's impossible to
do :-(.

Well, the dumb, brute-force way to do it would be something like this, I
guess:

# Assuming your array is called 'array'
require 'rubygems'
require 'activesupport' # What? I'm lazy. to_date is damn handy.

("2009-11-19".to_date.."2010-10-01".to_date).each do |date|
exists = array.find { |x| x[:date] == date.to_s }
next if exists # If the date is found in the array, next date please.
array << { :positive => "0", :neutral => "0", :total => "0", :date =>
date,
:negative => "1" }
end

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Aldric Giacomoni wrote:

Joao Silva wrote:

I have the following object as a result from MySQL:

[{:positive=>"0", :neutral=>"2", :total=>"5", :date=>"2009-12-01",
:negative=>"3"}, {:positive=>"3", :neutral=>"3", :total=>"7",
:date=>"2009-12-08", :negative=>"1"}, {:positive=>"1", :neutral=>"1",
:total=>"3", :date=>"2009-12-09", :negative=>"1"}]

I want to fill gaps (for example from 2009-11-19 till 2010-10-01) with
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>"HEREDATE",
:negative=>"1" - how i can do this in ruby? In MySQL it's impossible to
do :-(.

Alright... Now that I've helped you do what you asked for, please tell
us what you actually want to do, because actually filling up a hash with
default data is really not optimal.

I don't have choice: I need data formed like this to generate report
(chart) data. And i need for each day approporiate values.

···

--
Posted via http://www.ruby-forum.com/\.

Joao Silva wrote:

Yep, i understand, but it returns wrong value (and not sorted by date
;-():

Try this then.

("2009-11-11".to_date.."2010-01-01".to_date).each do |date|
  exists = result.find { |x| x[:date] == date.to_s }
  next if exists
  result << { :positive => "0", :neutral => "0", :total => "0",
              :date => date.to_s, :negative => "0" }
end
array.sort! { |a, b| a[:date].to_date <=> b[:date].to_date }

Just a teeny tiny little "to_s".
And sorting an array is a simple matter of looking up the sort method in
the rdoc (which IS your best friend).

···

--
Posted via http://www.ruby-forum.com/\.

Joao Silva wrote:

Aldric Giacomoni wrote:

Joao Silva wrote:

I have the following object as a result from MySQL:

[{:positive=>"0", :neutral=>"2", :total=>"5", :date=>"2009-12-01",
:negative=>"3"}, {:positive=>"3", :neutral=>"3", :total=>"7",
:date=>"2009-12-08", :negative=>"1"}, {:positive=>"1", :neutral=>"1",
:total=>"3", :date=>"2009-12-09", :negative=>"1"}]

I want to fill gaps (for example from 2009-11-19 till 2010-10-01) with
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>"HEREDATE",
:negative=>"1" - how i can do this in ruby? In MySQL it's impossible to
do :-(.

Alright... Now that I've helped you do what you asked for, please tell
us what you actually want to do, because actually filling up a hash with
default data is really not optimal.

I don't have choice: I need data formed like this to generate report
(chart) data. And i need for each day approporiate values.

You could check whether the data is in the array, and return the default
that you want if it's not in there.

Pseudo code:

From date1 to date2, do |date|
data = array.find { |x| x[:date] == date }
if data.nil?
   data = { your default hash }
end

do_whatever_you_want_with_data_here
end

Why do you have an array of hashes, anyway?
Why not a hash with the dates as keys and the rest of the hash as
values? a hash of hashes.

···

--
Posted via http://www.ruby-forum.com/\.

Maybe this is what the O.P. wants:

# Aldric Giacomoni's neat solution, modified slightly
require 'rubygems'
require 'activesupport' # What? I'm lazy. to_date is damn handy.

array = [
{:positive=>"0", :neutral=>"2", :total=>"5", :date=>"2009-12-01", :negative=>"3"},
  
{:positive=>"3", :neutral=>"3", :total=>"7", :date=>"2009-12-09", :negative=>"1"},
  
{:positive=>"1", :neutral=>"1", :total=>"3", :date=>"2009-12-05", :negative=>"1"}
]
default =
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>"HEREDATE", :negative=>"1"}
range = ("2009-12-01".to_date .. "2009.12.11".to_date)

range.each { |date|
  next if array.find { |row| row[:date].to_date == date.to_date }
  array << default =
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>"#
{date.to_s}", :negative=>"1"}
}

array.sort { |r1, r2| r1[:date] <=> r2[:date]}.each { |row| puts
row.inspect}

======= Result =======
{:neutral=>"2", :total=>"5", :date=>"2009-12-01", :negative=>"3", :positive=>"0"}
{:neutral=>"0", :total=>"0", :date=>"2009-12-02", :negative=>"1", :positive=>"0"}
{:neutral=>"0", :total=>"0", :date=>"2009-12-03", :negative=>"1", :positive=>"0"}
{:neutral=>"0", :total=>"0", :date=>"2009-12-04", :negative=>"1", :positive=>"0"}
{:neutral=>"1", :total=>"3", :date=>"2009-12-05", :negative=>"1", :positive=>"1"}
{:neutral=>"0", :total=>"0", :date=>"2009-12-06", :negative=>"1", :positive=>"0"}
{:neutral=>"0", :total=>"0", :date=>"2009-12-07", :negative=>"1", :positive=>"0"}
{:neutral=>"0", :total=>"0", :date=>"2009-12-08", :negative=>"1", :positive=>"0"}
{:neutral=>"3", :total=>"7", :date=>"2009-12-09", :negative=>"1", :positive=>"3"}
{:neutral=>"0", :total=>"0", :date=>"2009-12-10", :negative=>"1", :positive=>"0"}
{:neutral=>"0", :total=>"0", :date=>"2009-12-11", :negative=>"1", :positive=>"0"}

HTH,
Richard

···

On Dec 10, 1:56 pm, Aldric Giacomoni <ald...@trevoke.net> wrote:

Joao Silva wrote:
> Aldric Giacomoni wrote:
>> Joao Silva wrote:
>>> I have the following object as a result from MySQL:

>>> [{:positive=>"0", :neutral=>"2", :total=>"5", :date=>"2009-12-01",
>>> :negative=>"3"}, {:positive=>"3", :neutral=>"3", :total=>"7",
>>> :date=>"2009-12-08", :negative=>"1"}, {:positive=>"1", :neutral=>"1",
>>> :total=>"3", :date=>"2009-12-09", :negative=>"1"}]

>>> I want to fill gaps (for example from 2009-11-19 till 2010-10-01) with
>>> {:positive=>"0", :neutral=>"0", :total=>"0", :date=>"HEREDATE",
>>> :negative=>"1" - how i can do this in ruby? In MySQL it's impossible to
>>> do :-(.

>> Alright... Now that I've helped you do what you asked for, please tell
>> us what you actually want to do, because actually filling up a hash with
>> default data is really not optimal.

> I don't have choice: I need data formed like this to generate report
> (chart) data. And i need for each day approporiate values.

You could check whether the data is in the array, and return the default
that you want if it's not in there.

Pseudo code:

From date1 to date2, do |date|
data = array.find { |x| x[:date] == date }
if data.nil?
data = { your default hash }
end

do_whatever_you_want_with_data_here
end

Why do you have an array of hashes, anyway?
Why not a hash with the dates as keys and the rest of the hash as
values? a hash of hashes.
--
Posted viahttp://www.ruby-forum.com/.

This is a little cleaner. with the same result:

# Aldric Giacomoni's neat solution, modified slightly
require 'rubygems'
require 'activesupport' # What? I'm lazy. to_date is damn handy.

array = [
{:positive=>"0", :neutral=>"2", :total=>"5", :date=>"2009-12-01", :negative=>"3"},
  
{:positive=>"3", :neutral=>"3", :total=>"7", :date=>"2009-12-09", :negative=>"1"},
  
{:positive=>"1", :neutral=>"1", :total=>"3", :date=>"2009-12-05", :negative=>"1"}
]
range = ("2009-12-01".to_date .. "2009.12.11".to_date)

range.each { |date|
  next if array.find { |row| row[:date] == date.to_s}
  array <<
{:positive=>"0", :neutral=>"0", :total=>"0", :date=>date.to_s, :negative=>"1"}
}

sorted = array.sort { |r1, r2| r1[:date] <=> r2[:date] }
sorted.each { |row| puts row.inspect}

HTH,
Richard