我有以下ruby代码:
@averages = Array.new
weekly_averages.each do |average|
yr = average.date.to_s[0..3].to_i
wk = average.date.to_s[4..5].to_i
prices = Array.new
prices << { locale: average.locale, price: average.average }
@averages << { :year => yr, :week => wk, :prices => prices }
end
这会导致像这样的表
Week Ending Date Product Nairobi Mombasa Kisumu Nakuru Eldoret
38 2014-09-21 Dry Maize 3,140.00
38 2014-09-21 Dry Maize 2,216.67
38 2014-09-21 Dry Maize 2,513.13
38 2014-09-21 Dry Maize 3,362.50
38 2014-09-21 Dry Maize 2,311.43`
如何将其折叠为一行,例如:
Week Ending Date Product Nairobi Mombasa Kisumu Nakuru Eldoret
38 2014-09-21 Dry Maize 3,140 2216.67 2,513.13 3,362.50 2,311.43
答案 0 :(得分:1)
您可以使用Enumerable#group_by并按已按日期分组的元素进行迭代:
@averages = weekly_averages.group_by(&:date).map do |date, averages|
yr = date.to_s[0..3].to_i
wk = date.to_s[4..5].to_i
prices = averages.map { |average| { locale: average.locale, price: average.average } }
{ year: yr, week: wk, prices: prices }
end
答案 1 :(得分:0)
让我们从创建一些数据开始:
A = Struct.new :week, :ending_date, :product, :locale, :average
weekly_averages = [
A.new(38, '2014-09-21', 'Dry Maize', 'Kakuru', '3362.50'),
A.new(38, '2014-09-21', 'Dry Maize', 'Mombasa', '2216.67'),
A.new(38, '2014-09-21', 'Dry Maize', 'Kisuma', '2513.13'),
A.new(38, '2014-09-21', 'Dry Maize', 'Nairobi', '3140.00'),
A.new(38, '2014-09-21', 'Dry Maize', 'Eldoret', '2311.43'),
A.new(39, '2014-09-28', 'Dry Maize', 'Kakuru', '3105.61'),
A.new(39, '2014-09-28', 'Dry Maize', 'Mombasa', '2060.12'),
A.new(38, '2014-09-21', 'Coffee', 'Eldoret', '1841.43'),
A.new(38, '2014-09-21', 'Coffee', 'Kakuru', '2187.66'),
]
您会看到我通过为第二个产品('Coffee'
)和第二周(周39
)添加结果来修改您的示例。此外,并非所有语言环境都具有添加结果的值。
我假设结束日期仅取决于一周。如果是这样,我们可以使用哈希处理它(如果没有,你可以对待它,我已经处理了下面的其他属性):
week_end_date = weekly_averages.each_with_object({}) { |i,h|
h[i.week] = i.ending_date }
#=> {38=>"2014-09-28", 39=>"2014-09-28"}
你想以什么顺序排行?我假设你想要按周,按产品每周订购。 (如果您想要不同的订购,只需根据需要更改以下内容。)您想要产品的顺序是什么?按字母顺序排列?作为指定?我假设您要指定产品订单:
products = ['Dry Maize', 'Coffee']
#=> ["Dry Maize", "Coffee"]
我们需要一个新的数据结构,其元素的排序与表的行相同,我将首先创建一个散列,其键是用于排序数据的两个属性的数组(week
和{{1 }})。这使用方法Hash#update(aka product
)的形式,该方法使用块(此处为merge!
)来确定合并的两个哈希中存在的键的值:
{ |_,o,n| o.merge(n)}
现在使用Enumerable#sort_by对averages = weekly_averages.each_with_object({}) { |i,h|
h.update([i.week, i.product]=>{ i.locale => i.average }) { |_,o,n|
o.merge(n) } }
#=> {[38, "Dry Maize"]=>
# {"Kakuru"=>"3362.50", "Mombasa"=>"2216.67", "Kisuma"=>"2513.13",
# "Nairobi"=>"3140.00", "Eldoret"=>"2311.43"},
# [39, "Dry Maize"]=>{"Kakuru"=>"3105.61", "Mombasa"=>"2060.12"},
# [38, "Coffee"]=>{"Eldoret"=>"1841.43", "Kakuru"=>"2187.66"}}
的元素进行排序,然后将结果(键值对数组)转换回哈希值;
averages
我们还有两件事需要指明。第一个是语言环境(列)的顺序:
sorted_averages = Hash[averages.sort_by { |(week, product),_|
[week, products.index(product)] }]
#=> {[38, "Dry Maize"]=>{"Kakuru"=>"3362.50", "Mombasa"=>"2216.67",
# "Kisuma"=>"2513.13", "Nairobi"=>"3140.00", "Eldoret"=>"2311.43"},
# [38, "Coffee"]=>{"Eldoret"=>"1841.43", "Kakuru"=>"2187.66"},
# [39, "Dry Maize"]=>{"Kakuru"=>"3105.61", "Mombasa"=>"2060.12"}}
最后,我们需要指定每列的宽度和对齐方式。为此,我将使用键locales = %w| Nairobi Mombasa Kisuma Kakuru Eldoret |
#=> ["Nairobi", "Mombasa", "Kisuma", "Kakuru", "Eldoret"]
(列标签),:label
(列宽)和:width
(左侧调整,居中或右侧调整)创建一个哈希数组。该数组的i th 元素对应于i th 列:
:alignment
我们现在可以打印表了。首先是列标题:
fields = [{ label: "Week", width: 4, alignment: :left},
{ label: "Ending Date", width: "Ending Date".size + 2,
alignment: :center },
{ label: "Product",
width: (1+(weekly_averages.map {|i|
i.product}.uniq << "Product").map(&:size).max),
alignment: :left }
]
#=> [{:label=>"Week", :width=>4, :alignment=>:left},
# {:label=>"Ending Date", :width=>13, :alignment=>:center},
# {:label=>"Product", :width=>10, :alignment=>:left}]
locales.each { |l| fields <<
{ label: l,
width: [1+l.size, 2 + weekly_averages.map { |i| i.average.size }.max].max,
alignment: :right
}
}
fields
#=> [{:label=>"Week", :width=>4, :alignment=>:left},
# {:label=>"Ending Date", :width=>13, :alignment=>:center},
# {:label=>"Product", :width=>10, :alignment=>:left},
# {:label=>"Nairobi", :width=>11, :alignment=>:right},
# {:label=>"Mombasa", :width=>11, :alignment=>:right},
# {:label=>"Kisumu", :width=>11, :alignment=>:right},
# {:label=>"Nakuru", :width=>11, :alignment=>:right},
# {:label=>"Eldoret", :width=>11, :alignment=>:right}]
然后身体:
fields.each do |h|
case h[:alignment]
when :left then print h[:label].ljust(h[:width])
when :center then print h[:label].center(h[:width])
when :right then print h[:label].rjust(h[:width])
end
end
puts