Display all values ​​for each date in JSON

I have the following JSON:

{ "groups" : [ { "values": "21", "date": "2013-02-22" }, { "values": "25", "date": "2013-02-22" }, { "values": "20", "date": "2013-02-22" }, { "values": "19", "date": "2013-02-22" }, { "values": "42", "date": "2013-02-10" }, { "values": "30", "date": "2013-02-10" }, { "values": "11", "date": "2013-02-10" } ] } 

I have values ​​and a date already retrieved in the Ruby class. I want to find the "highest" and "lowest" values ​​for each date. How to do it?

I also want to create parallel arrays for the same. For instance:

 low = [12, 22, 11, 45] high = [34, 50, 15, 60] dates = ["2013-02-22", "2013-02-10", "2013-02-06", "2013-02-01"] 

I would also like to display all the values ​​for each date.

Can someone please give me some direction for this?

0
source share
2 answers

If str is your JSON string:

 require 'json' arr = JSON.parse(str)["groups"] #=> [{"values"=>"21", "date"=>"2013-02-22"}, # {"values"=>"25", "date"=>"2013-02-22"}, # {"values"=>"20", "date"=>"2013-02-22"}, # {"values"=>"19", "date"=>"2013-02-22"}, # {"values"=>"42", "date"=>"2013-02-10"}, # {"values"=>"30", "date"=>"2013-02-10"}, # {"values"=>"11", "date"=>"2013-02-10"}] by_date = arr.each_with_object(Hash.new {|h,k| h[k] = []}) { |g,h| h[g["date"]] << g["values"].to_i } # => {"2013-02-22"=>[21, 25, 20, 19], "2013-02-10"=>[42, 30, 11]} dates = by_date.keys #=> ["2013-02-22", "2013-02-10"] min_vals, max_vals = *by_date.map { |_,vals| vals.minmax } #=> [[19, 25], [11, 42]] min_vals #=> [19, 25] max_vals #=> [11, 42] 

The Enumerable # each_with_object method takes an argument, which is the initial value of the object that will be created and returned by the method. This value is set by the second block variable, h . I made this argument an empty hash with the default value given by the block:

 {|h,k| h[k] = []} 

What is the default value? All this means that if the hash h does not have the key k , h[k] returns an empty array. See how it works here.

Initially, h #=> {} and each_with_object sets the first block variable g be equal to the first value of arr :

 g = {"values"=>"21", "date"=>"2013-02-22"} 

and the block is calculated:

 h[g["date"]] << g["values"].to_i #=> h["2013-02-22"] << 21 

Since h does not have the key "2013-02-22" , h["2013-02-22"] first set to the default value, an empty array:

 h["2013-02-22"] = [] 

then

 h["2013-02-22"] << 21 #=> [21] h #=> {"2013-02-22"=>[21]} 

When the following arr value is passed to the block:

 g = {"values"=>"25", "date"=>"2013-02-22"} 

and h has the meaning indicated above. So now the block calculation:

 h[g["date"]] << g["values"].to_i #=> h["2013-02-22"] << 25 #=> [21, 25] h #=> {"2013-02-22"=>[21, 25]} 

The default value is not used this time, since h has the key "2013-02-22" .

One more thing may require an explanation: "splat" * in:

 min_vals, max_vals = *by_date.map { |_,vals| vals.minmax } 

We see that:

 by_date.map { |date, vals| vals.minmax } #=> [[19, 25], [11, 42]] 

If *by_date.map { |date, vals| vals.minmax } *by_date.map { |date, vals| vals.minmax } is on the right side of the equality, splat forces two elements [[19, 25], [11, 42]] to be assigned to the variables on the left side of the equality, using a parallel assignment. A strange and wonderful splat operator should be in every Rubiest trick bag.

Since I do not use date in the calculation of the block, I paid attention to this by replacing date with the local variable _ .

Edit: To answer the question you sent in the comment if:

 id = [1,1,1,2,2,3,4] high = [100,100,100,90,90,100,100] low = [20,20,20,10,10,30,40] 

and I understand your question correctly, you can first calculate:

 indices = id.each_with_index.to_a.uniq(&:first).map(&:last) #=> [0, 3, 5, 6] 

Then three arrays are required:

 id.values_at(*indices) #=> [1, 2, 3, 4] high.values_at(*indices) #=> [100, 90, 100, 100] low.values_at(*indices) #=> [20, 10, 30, 40] 
+1
source

You can group_by :date and repeat these dates. Then create an array from :values in the group.

Then use minmax to get the correct values ​​and transpose final array to get your arrays and assign dates low and high.

 json = { "groups": [ { "values": "21", "date": "2013-02-22" }, { "values": "25", "date": "2013-02-22" }, { "values": "20", "date": "2013-02-22" }, { "values": "19", "date": "2013-02-22" }, { "values": "42", "date": "2013-02-10" }, { "values": "30", "date": "2013-02-10" }, { "values": "11", "date": "2013-02-10" } ] } dates, low, high = json[:groups].group_by { |g| g[:date] }.map do |date, grouped| values = grouped.map { |group| group[:values] } [date, *values.minmax] end.transpose # => => [["2013-02-22", "2013-02-10"], ["19", "11"], ["25", "42"]] dates # => ["2013-02-22", "2013-02-10"] low # => ["19", "11"] high # => ["25", "42"] 
+1
source

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


All Articles