Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hash/Ruby - Select last 4 values (to average) in hash

I have a hash, that I select all the data for a dashboard to display performance, since displaying the latest value isn't always helpful, I'm trying to select the last 4 values from a hash.

I have attempted the thing.last(4), but to no avail.

Code is below, essentially trying to display the last 4 from top_points, or average points.

Note: Ruby 1.9

metric.sort.each do |key, value|
  top_point = { x: Time.parse(key).to_time.to_i, y: value['top_10'] }
  top_points << top_point

  average_point = { x: Time.parse(key).to_time.to_i, y: value['average'] }
  average_points << average_point
end
like image 619
Nomad Avatar asked Feb 15 '26 23:02

Nomad


2 Answers

The following uses Hash#select to avoid the need to convert the hash to an array, manipulate the array and then convert it back to a hash.

h = { "b"=>1, "d"=>6, "f"=>3, "e"=>1, "c"=>3, "a"=>7 }
sz = h.size
  #=> 6
h.select { (sz -= 1) < 4 }
  #=> {"f"=>3, "e"=>1, "c"=>3, "a"=>7} 

Alternatively, if using Ruby 2.5+ one could use Hash#slice:

h.slice(*h.keys[-4..-1])
  #=> {"f"=>3, "e"=>1, "c"=>3, "a"=>7}

and if using Ruby 2.6+ one could employ an Endless range:

h.slice(*h.keys[-4..])
  #=> {"f"=>3, "e"=>1, "c"=>3, "a"=>7}
like image 104
Cary Swoveland Avatar answered Feb 17 '26 15:02

Cary Swoveland


in order to get the last four elements of your hash, you should first map it as an array, get the indexes desired and then transform again the array into an hash.

For example:

2.2.1 :001 > hash = {a: 1, b: 2, c: 3, d: 4, e: 5}
 => {:a=>1, :b=>2, :c=>3, :d=>4, :e=>5} 
2.2.1 :002 > hash.map{|h| h}[-4..-1].to_h
 => {:b=>2, :c=>3, :d=>4, :e=>5} 

In your specific case, the code might look like this:

metric.sort.map{|h| h}[-4..-1].to_h.each do |key, value|
    top_point = { x: Time.parse(key).to_time.to_i, y: value['top_10'] }
    top_points << top_point

    average_point = { x: Time.parse(key).to_time.to_i, y: value['average'] }
    average_points << average_point
  end

Another way to write it could be:

last_four_metrics = metric.sort.map{|h| h}[-4..-1].to_h
top_points = last_four_metrics.map{|k, v| { x: Time.parse(k).to_time.to_i, y: v['top_10'] }}
average_points = last_four_metrics.map{|k, v| { x: Time.parse(k).to_time.to_i, y: v['average'] }}

Update: compatibility with Ruby 1.9

last_four_metrics = Hash[ metric.sort.map{|h| h}[-4..-1] ]

top_points = last_four_metrics.map{|k, v| { x: Time.parse(k).to_time.to_i, y: v['top_10'] }}
average_points = last_four_metrics.map{|k, v| { x: Time.parse(k).to_time.to_i, y: v['average'] }}
like image 36
mabe02 Avatar answered Feb 17 '26 13:02

mabe02



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!