Home > Net >  How to pull highest value out of an array and double its value
How to pull highest value out of an array and double its value

Time:02-01

So I have some code which gives me combinations. I'd like to find the highest driver_points value from each combination and then double its value.

Here's my code currently:

     # DRIVER AND TEAM ARRAYS
     driver_points = { "john" => 18.1, "mike" => 19.3, "paul" => 15.6, "mark" => 1.1 }
     driver_price = { "john" => 4.0, "mike" => 5.0, "paul" => 6.0, "mark" => 2.1 }
     team_points = { "cowboys" => 20.1, "bears" => 19.3, "lions" => 15.6, "united" => 2.8 }
     team_price = { "cowboys" => 1.0, "bears" => 2.0, "lions" => 3.0, "united" => 2.4 }

    # DEFINE VARIABLE AND TARGET
     teams = team_price.keys
     drivers = driver_price.keys
     target = 13.5

    # CREATE METHOD TO SUM BOTH PRICES AND POINTS FOR GIVEN COMBINATION
    def add_up(combo, ht, hd)
      t, d = combo
      ht[t]   hd.values_at(*d).sum
    end

    # ALL POSSIBLE COMBINATIONS OF TEAM AND DRIVERS
    all_driver_combos = drivers.combination(3).to_a
    all_combos = teams.product(all_driver_combos)

    # SHOW ALL COMBOS WHERE SUM DOES NOT EXCEED TARGET
    valid_combos = all_combos.select do |c|
      add_up(c, team_price, driver_price) <= target
    end

    # SORT VALID COMBOS BY SUM OF POINTS FOR EACH ELEMENT
    ordered = valid_combos.sort_by do |c|
      -add_up(c, team_points, driver_points)
    end

    #OUTPUT
    @combo = ordered.map do |c|
      { c.join(" ")=>{ price: add_up(c, team_price, driver_price),
             points: add_up(c, team_points, driver_points).round(2) } }
    end

Which is currently outputting combinations (1 team and 3 drivers) based on the target value but sorted by highest points:

[{"cowboys john mike mark"=>{:price=>12.1, :points=>58.6}}, {"bears john mike mark"=>{:price=>13.1, :points=>57.8}}, {"cowboys john paul mark"=>{:price=>13.1, :points=>54.9}}, {"united john mike mark"=>{:price=>13.5, :points=>41.3}}]

I'd like to be able to find the highest driver, based on highest driver_points from each combo, and double its points value.

For example in my first outputted combination: {"cowboys john mike mark"=>{:price=>12.1, :points=>58.6}}

I want to be able to find the highest scoring driver of the three - this would be one of john, mike and mark as I don't want to include the team. Answer is Mike since he has 19.3 points. And then double Mike's driver points, which should then update the :points=> sum. Giving a new total points of 77.9. Also, I'd like to be able to move the highest points driver to the start of the driver combo for styling purposes in the view.

So my desired output is this:

Team Double Combo Price Points
cowboys mike john mark 12.1 77.9

CodePudding user response:

You have computed

valid_combos
  #=> [["cowboys", ["john", "mike", "mark"]],
  #    ["cowboys", ["john", "paul", "mark"]],
  #    ["bears",   ["john", "mike", "mark"]],
  #    ["united",  ["john", "mike", "mark"]]]

Consider the combo

c = ["cowboys", ["john", "mike", "mark"]]
        20.1      18.1    19.3     1.1
   

where the team points for "cowboys" and the driver points for each of the three drivers in this combination are shown above. (Someone needs to have a word with Mark.)

The total points for this combination is seen to be

add_up(c, team_points, driver_points)
  #=> 58.6

To this we wish to add 19.3 points, which are driver points for "Mike" as he has the most points among the combination's three drivers:

58.6   19.3
  #=> 77.9

We can do this in code as follows.

def add_dbl(combo, team_points, driver_points)
  t, ds = combo
  dmax = ds.max_by { |d| driver_points[d] }
  driver_points[dmax]   add_up(combo, team_points, driver_points)
end

For the combination c defined above,

add_dbl(c, team_points, driver_points)
  #=> 77.9

as expected. We may now use add_dbl in place of add_up to sort the combinations.

ordered = valid_combos.sort_by do |c|
  -add_dbl(c, team_points, driver_points)
end
  #=> [["cowboys", ["john", "mike", "mark"]],
  #    ["bears", ["john", "mike", "mark"]],
  #    ["cowboys", ["john", "paul", "mark"]],
  #    ["united", ["john", "mike", "mark"]]]

The following code rearranges the drivers so that the driver with the highest driver points appears first in each array of drivers in ordered.

ordered.each do |_t,ds|
  imax = ds.each_index.max_by { |i| driver_points[ds[i]] }  
  ds.unshift(ds.delete_at(imax))
end
  #=> [["cowboys", ["mike", "john", "mark"]],
  #    ["bears", ["mike", "john", "mark"]],
  #    ["cowboys", ["john", "paul", "mark"]],
  #    ["united", ["mike", "john", "mark"]]]

See Array#each_index, Enumerable#max_by, Array#unshift and Array#delete_at. Note that Array#each returns its receiver (ordered) but we are modifying that array.


To merely sort the drivers, from highest to lowest driver points, modify the above expression as follows.

ordered.each do |_t,ds|
  ds.sort_by! { |d| -driver_points[d] }
end
  #=> [["cowboys", ["mike", "john", "mark"]],
  #    ["bears", ["mike", "john", "mark"]],
  #    ["cowboys", ["john", "paul", "mark"]],
  #    ["united", ["mike", "john", "mark"]]]

Coincidently, these arrays of drivers are no different than the ones above.

See Array#sort_by!.

  • Related