aprogrammer
aprogrammer

Reputation: 45

Ruby: looping over two hashes simultaneously with one being a nested hash

I am a newbie to coding and to ruby and have an assignment for class. We are supposed to take a data set from excel of taxi drivers and find the number of rides and amount earned per driver. We are free to structure the code in any way we want. Below is my code.

What I am trying to do is tally the number of rides and store them in the hash rides_per_driver. However, with the ifstatement I get a "no implicit conversion of Array into Integer (TypeError)." How do I get the program to take the keysfor rides_per_driverand iterate over the hash rides?

Any help is appreciated. Thank you

# Stored rides data.
rides = {
  ride_1: {
    driver_id: "DR0004",
    date: "3rd Feb 2016",
    cost: 5,
    rider_id: "RD0022",
    rating: 5
  },

  ride_2: {
    driver_id: "DR0001",
    date: "3rd Feb 2016",
    cost: 10,
    rider_id: "RD0003",
    rating: 3
  },

 ride_3: {
    driver_id: "DR0002",
    date: "3rd Feb 2016",
    cost: 25,
    rider_id: "RD0073",
    rating: 5
  }
}



# iterate over the hash of hashes. If the driver id is x then
# add one ride to the tally.



# Storage for number of rides per driver
rides_per_driver = {
  "DR0001" => 0,
  "DR0002" => 0,
  "DR0003" => 0,
  "DR0004" => 0
}
amount_earned_per_driver = []

rides_per_driver.each do |x|
  if rides_per_driver.has_key?(rides_per_driver[x])
    rides.each do|ride_num, ride_data|
      rides.each do |k, v|
        rides_per_driver += 1
      end
    end
  else
    rides.each do|ride_num, ride_data|
      rides.each do |k, v|
        rides_per_driver = 1
      end
    end
  end


end

Upvotes: 1

Views: 1154

Answers (3)

dawg
dawg

Reputation: 104111

First, let's change the data you have to two drivers with one, "DR0004", having two rides:

rides = {
    ride_1: {
        driver_id: "DR0004",
        date: "3rd Feb 2016",
        cost: 5,
        rider_id: "RD0022",
        rating: 5
    },

    ride_2: {
        driver_id: "DR0004",
        date: "3rd Feb 2016",
        cost: 10,
        rider_id: "RD0003",
        rating: 3
    },

 ride_3: {
        driver_id: "DR0002",
        date: "3rd Feb 2016",
        cost: 25,
        rider_id: "RD0073",
        rating: 5
    }
}

You can use .group_by to get a hash of drive drives by driver:

rides_by_driver=rides.group_by { |k, h| h[:driver_id] }
                     .map { |k, v| [k, v.to_h] }.to_h
{"DR0004"=>{:ride_1=>{:driver_id=>"DR0004", :date=>"3rd Feb 2016", :cost=>5, :rider_id=>"RD0022", :rating=>5}, :ride_2=>{:driver_id=>"DR0004", :date=>"3rd Feb 2016", :cost=>10, :rider_id=>"RD0003", :rating=>3}}, "DR0002"=>{:ride_3=>{:driver_id=>"DR0002", :date=>"3rd Feb 2016", :cost=>25, :rider_id=>"RD0073", :rating=>5}}}

Then you can add up the amounts per driver:

rides_by_driver.map { |k,v| [k, v.inject(0) { |sum,(k,v)| sum+=v[:cost] } ] }.to_h
{"DR0004"=>15, "DR0002"=>25}

Or, if you want to know the rides per driver:

rides_by_driver.map { |k,v| [k, v.length] }.to_h
{"DR0004"=>2, "DR0002"=>1}

Upvotes: 1

Cary Swoveland
Cary Swoveland

Reputation: 110755

rides = [
  { driver_id: "DR0004", date: "3rd Feb 2016", cost:  5, rider_id: "RD0022", rating: 5 },
  { driver_id: "DR0001", date: "3rd Feb 2016", cost: 10, rider_id: "RD0003", rating: 3 },
  { driver_id: "DR0002", date: "3rd Feb 2016", cost: 25, rider_id: "RD0073", rating: 5 },
  { driver_id: "DR0004", date: "3rd Feb 2016", cost:  5, rider_id: "RD0022", rating: 5 },
]

rides.each_with_object({}) do |ride, h|
  h.update(ride[:driver_id]=>{ rides: 1, earnings: ride[:cost] }) do |_,o,n|
    { rides: o[:rides]+1, earnings: o[:earnings]+n[:earnings] }
  end 
end
  #=> {"DR0004"=>{:rides=>2, :earnings=>10},
  #    "DR0001"=>{:rides=>1, :earnings=>10},
  #    "DR0002"=>{:rides=>1, :earnings=>25}}

This uses the form of Hash#update (aka merge!) that employs a block to determine the values of keys present in both hashes being merged. See the doc for details, especially the definitions of the three block variables (_, o and n). (I've used an underscore in place of the common key to signify that the key is not used in the block calculation.)

Upvotes: 2

ydaniju
ydaniju

Reputation: 400

rides = {
  ride_1: {
    driver_id: 'DR0004',
    date: '3rd Feb 2016',
    cost: 5,
    rider_id: 'RD0022',
    rating: 5
  },

  ride_2: {
    driver_id: 'DR0001',
    date: '3rd Feb 2016',
    cost: 10,
    rider_id: 'RD0003',
    rating: 3
  },

  ride_3: {
    driver_id: 'DR0002',
    date: '3rd Feb 2016',
    cost: 25,
    rider_id: 'RD0073',
    rating: 5
  }
}

# iterate over the hash of hashes. If the driver id is x then
# add one ride to the tally.

# Storage for number of rides per driver
rides_per_driver = {
  'DR0001' => 0,
  'DR0002' => 0,
  'DR0003' => 0,
  'DR0004' => 0
}
amount_earned_per_driver = []

I think this all you need to do to get your rides_per_driver updated

rides.each do |_key, val|
  rides_per_driver[val[:driver_id]] += 1
end

You iterate through the rides and get the rider_id for each ride which is val[:driver_id] in the solution. You then use it to update the value of each driver in rides_per_driver.

Upvotes: 1

Related Questions