Armando Quiroga
Armando Quiroga

Reputation: 15

Maximum value and percentile in array

I have the following array:

array = [{"student" => 1, "cost" => 2, "university" => 2, "room" => 2},
         {"student" => 1, "cost" => 5, "university" => 2, "room" => 3},
         {"student" => 1, "cost" => 1, "university" => 3, "room" => 1},
         {"student" => 2, "cost" => 1, "university" => 1, "room" => 3},
         {"student" => 2, "cost" => 2, "university" => 2, "room" => 2},
         {"student" => 2, "cost" => 4, "university" => 1, "room" => 1}]

I want an array that only has the maximum value and the percentile 95 of "cost", i.e.,

array = [{"student" => 1, "cost_max" => 5, "university" => 2, "room" => 3, "cost_per95" => 4.7},
         {"student" => 2, "cost_max" => 4, "university" => 1, "room" => 1, "cost_per95"=> 3.9}

I have applied this:

groupedmax  = array.group_by {|h| h["student"]}
keysmax = groupedmax.keys
arrmax = keysmax.map {|k| [k, groupedmax[k].max_by {|h| h["cost"]}]}
table_max = arrmax.map { |ts| ts[1] }
# => [{"student"=>1, "cost"=>5, "university"=>2, "room"=>3},
#   {"student"=>2, "cost"=>4, "university"=>1, "room"=>1}]

but I do not know how to add the percentile 95 to that array. A way to calculate percentile is:

def percentile(values, percentile)
  values_sorted = values.sort
  k = (percentile*(values_sorted.length-1)+1).floor - 1
  f = (percentile*(values_sorted.length-1)+1).modulo(1)

  return values_sorted[k] + (f * (values_sorted[k+1] - values_sorted[k]))
end

Attentive to your comments.

Upvotes: 0

Views: 201

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110725

def doit(arr)
  arr.group_by { |h| h["student"] }.   
      map do |_,a|
        costs = a.map { |h| h['cost'] }
        imax = costs.each_index.max_by { |i| costs[i] }
        a[imax].merge('cost_per95'=>percentile(costs, 0.95).round(1))
      end
end

doit array
  #=> [{"student"=>1, "cost"=>5, "university"=>2, "room"=>3, "cost_per95"=>4.7},
  #    {"student"=>2, "cost"=>4, "university"=>1, "room"=>1, "cost_per95"=>3.9}]

array = [{"student" => 1, "cost" => 2, "university" => 2, "room" => 2},
         {"student" => 1, "cost" => 5, "university" => 2, "room" => 3},
         {"student" => 1, "cost" => 1, "university" => 3, "room" => 1},
         {"student" => 2, "cost" => 1, "university" => 1, "room" => 3},
         {"student" => 2, "cost" => 3, "university" => 2, "room" => 2}, 
         {"student" => 2, "cost" => 4, "university" => 1, "room" => 1}]
  #=> [{"student"=>1, "cost"=>5, "university"=>2, "room"=>3, "cost_per95"=>4.7},
  #    {"student"=>2, "cost"=>4, "university"=>1, "room"=>1, "cost_per95"=>3.9}]

Upvotes: 1

Kshitij
Kshitij

Reputation: 339

You can use merge to add keys in that hash.
Try this,

table_max = arrmax.map { |ts| ts[1].merge("cost_per95": ts[1]["cost"] * 0.95) }

or you can try this to do all your calculations in just one line

array.group_by{ |x| x["student"] }.values.map{ |gp| gp.max_by{ |st| st["cost"] }.merge({ "cost_per95": "Your calculations" })}

Upvotes: 0

Related Questions