require 'rubygems'
require 'active_record'
class Product < ActiveRecord::Base
has_many :purchases
end
class Purchase < ActiveRecord::Base
belongs_to :store
end
class Store < ActiveRecord::Base
end
sales = {
'Cardstock' => {
'NYC' => 34, 'L.A.' => 30, 'ATL' => 31, 'HSV' => 25, 'PDX' => 37,
'DAL' => 26, 'NASH' => 27, 'CHI' => 44
},
'Foldes' => {
'NYC' => 118, 'L.A.' => 78, 'ATL' => 67, 'HSV' => 58, 'PDX' => 59,
'DAL' => 68, 'NASH' => 73, 'CHI' => 97
},
'Paper' => {
'NYC' => 121, 'L.A.' => 64, 'ATL' => 66, 'HSV' => 67, 'PDX' => 61,
'DAL' => 69, 'NASH' => 59, 'CHI' => 81
},
'Envelopes' => {
'NYC' => 123, 'L.A.' => 62, 'ATL' => 67, 'HSV' => 64, 'PDX' => 57,
'DAL' => 61, 'NASH' => 75, 'CHI' => 82
}
}
#total count of all sales, to get maximm 'id' index
total_sales = 0
sales.each_value {|sales_by_city|
total_sales += sales_by_city.values.inject(0) {|sum, value| sum + value}
}
puts total_sales
Refactorings
No refactoring yet !
Adam
October 25, 2010, October 25, 2010 16:45, permalink
total_sales = sales.values.sum { |value| value.values.sum }
Vincent Durand
October 25, 2010, October 25, 2010 21:02, permalink
Active Record require with this method. I really like active record sum elegant tricks !
total_sales = sales.values.sum(&:values).sum
Rick DeNatale
October 26, 2010, October 26, 2010 02:31, permalink
Like this?
puts sales.values.inject(0) {|total_sales, product_sales_by_city|
total_sales + product_sales_by_city.values.inject(0) { |product_sales, city_sales| product_sales + city_sales}
}
A. Lester Buck III
October 27, 2010, October 27, 2010 00:35, permalink
Hey guys, thanks for the refactorings! I was looking for Rick's form, but I really like the ActiveRecord forms, too.
I was reading the book "Ruby in Practice", and Chapter 1 shows how much can be done in just forty odd lines of Ruby. Except the online code is missing the data set used in the example, or how to load the database. Here is the first chapter online:
\nhttp://www.manning.com/mcanally/Samplechapter1.pdf
[Note: I could not get Scruffy to work at all. I finally substituted Ruffy to generate the PNG, and that worked fine.]
So I wrote some code to load the database, and back-generated the sales data from the one figure given. Given the specific format (nested hash) I picked to hold the sales data, I wanted to find the total number of records to be loaded, so I could then randomize them as I loaded the database.
# random list of sale ndices
index_list = (1..total_sales).to_a.shuffle
This required summing over the nested sales data.
I have been reading "Refactoring: Ruby Edition", and I now see any pattern that looks like the following as a code smell to be ruthlessly eliminated in favor of the Ruby idiomatic versions:
array = []
.each {
array << item
}
or
sum = 0
.each {
sum += item
}
But I can't think of a way to sum over all the sales data without using just such aform. Is there a way to refactor to a double inject for this nested sum, avoiding explicitly initializing a counter? Feel free to reorganize the input data hash/whatever to make that happen.
"I've got that Ruby functional idiom religion!" :-)
Thanks!