2016-03-23 17 views
0

Bir karma bu değerleri vardır:Ruby - Belirli bir tarihe dayalı bir hash değeri nasıl hesaplanır (= anahtar)?

{nil=>0, 
Thu, 03 Dec 2015=>#<BigDecimal:7ff496381db8,'0.151875E2',18(27)>, 
Fri, 04 Dec 2015=>#<BigDecimal:7ff496381cf0,'0.214375E2',18(27)>, 
Wed, 09 Dec 2015=>#<BigDecimal:7ff496381c28,'0.6229E2',18(27)>, 
Thu, 10 Dec 2015=>#<BigDecimal:7ff496381b60,'0.1243E2',18(27)>, 
Fri, 11 Dec 2015=>#<BigDecimal:7ff496381a98,'0.1243E2',18(27)>, 
Mon, 14 Dec 2015=>#<BigDecimal:7ff4963819d0,'0.6611E2',18(27)>, 
Tue, 15 Dec 2015=>#<BigDecimal:7ff496381908,'0.625E1',18(18)>, 
Wed, 16 Dec 2015=>#<BigDecimal:7ff496381840,'0.73345E2',18(27)>, 
Thu, 17 Dec 2015=>#<BigDecimal:7ff496381778,'0.31845E2',18(27)>, 
Fri, 18 Dec 2015=>#<BigDecimal:7ff4963816b0,'0.409225E2',18(27)>, 
Mon, 21 Dec 2015=>#<BigDecimal:7ff4963815e8,'0.8019E2',18(27)>, 
Mon, 28 Dec 2015=>#<BigDecimal:7ff496381520,'0.3125E2',18(27)>, 
Mon, 04 Jan 2016=>#<BigDecimal:7ff496381458,'0.125E2',18(27)>, 
Wed, 06 Jan 2016=>#<BigDecimal:7ff496381390,'0.625E2',18(27)>, 
Thu, 07 Jan 2016=>#<BigDecimal:7ff4963812c8,'0.9111E2',18(27)>, 
Fri, 08 Jan 2016=>#<BigDecimal:7ff4963811d8,'0.11972E3',18(27)>, 
Mon, 11 Jan 2016=>#<BigDecimal:7ff4963810e8,'0.5022E2',18(27)>, 
Wed, 13 Jan 2016=>0, Thu, 14 Jan 2016=>0, Fri, 15 Jan 2016=>0, 
Wed, 09 Mar 2016=>#<BigDecimal:7ff496380eb8,'0.258125E2',18(27)>, 
Tue, 15 Mar 2016=>#<BigDecimal:7ff496380da0,'0.631825E2',18(27)>, 
Wed, 16 Mar 2016=>#<BigDecimal:7ff496380cd8,'0.504225E2',18(27)>, 
Thu, 17 Mar 2016=>#<BigDecimal:7ff496380c10,'0.125E2',18(27)>, 
Fri, 18 Mar 2016=>#<BigDecimal:7ff496380b48,'0.631825E2',18(27)>, 
Mon, 21 Mar 2016=>#<BigDecimal:7ff496380a80,'0.167925E2',18(27)>, 
Tue, 22 Mar 2016=>0} 

Bazı takvim verileri (@dates) döngü ediyorum ve belirli yıl ve ay içeren iki değişken olsun buradan: Artık

@dates.each do |d| 
    current_yer = d.strftime('%Y') #2016 
    current_month = d.strftime('%m') # 01 - january 

, Tarihleri ​​içeren değişkenlerim var, karmadaki tüm verilerin bir miktarını yazdırmak istiyorum; böylece bu durumda, ben çıktı olarak böyle bir şey olsun istiyorum:

2016 01:

özellikle karma tüm Ocak öğelerin SUM, bu SUM:

Mon, 04 Jan 2016=>#<BigDecimal:7ff496381458,'0.125E2',18(27)>, 

Wed, 06 Jan 2016=>#<BigDecimal:7ff496381390,'0.625E2',18(27)>, 

Thu, 07 Jan 2016=>#<BigDecimal:7ff4963812c8,'0.9111E2',18(27)>, 

Fri, 08 Jan 2016=>#<BigDecimal:7ff4963811d8,'0.11972E3',18(27)>, 

Mon, 11 Jan 2016=>#<BigDecimal:7ff4963810e8,'0.5022E2',18(27)>, 

Wed, 13 Jan 2016=>0, Thu, 14 Jan 2016=>0, Fri, 15 Jan 2016=>0, 

Bu nasıl yapılır?

Önceden teşekkür ederiz.

cevap

1

Sen select ve sum ile deneyebilirsiniz: İlk önce sizinkine benzer bir karma (h) inşa etsinler

@dates.select{|d, _| d.strftime('%Y %m') == '2016 01'}.values.sum 
+0

Not adımları tekrarlayın. –

0

örnek karma

Construct, ama biraz daha küçük:

g = { 
    "Thu, 03 Dec 2015"=> 1, 
    "Fri, 11 Dec 2015"=> 2, 
    "Mon, 14 Dec 2015"=> 3, 
    "Tue, 15 Dec 2015"=> 4, 
    "Wed, 16 Dec 2015"=> 5, 
    "Fri, 18 Dec 2015"=> 6, 
    "Mon, 21 Dec 2015"=> 7, 
    "Mon, 04 Jan 2016"=> 8, 
    "Fri, 08 Jan 2016"=> 9, 
    "Wed, 13 Jan 2016"=> 0, 
    "Thu, 14 Jan 2016"=> 0, 
    "Wed, 09 Mar 2016"=>10, 
    "Tue, 15 Mar 2016"=>11, 
    "Wed, 16 Mar 2016"=>12, 
    "Mon, 21 Mar 2016"=>13, 
    "Tue, 22 Mar 2016"=> 0 } 

require 'date' 
require 'bigdecimal' 

h = { nil=>0 }.tap { |h| g.each { |k,v| 
    h[Date.strptime(k, "%a, %d %b %Y")] = v.zero? ? 0 : BigDecimal.new(v) } } 

#=> {nil=>0, 
    # #<Date: 2015-12-03 ((2457360j,0s,0n),+0s,2299161j)> => 
    #  #<BigDecimal:7faef915c8e0,'0.1E1',9(27)>, 
    # #<Date: 2015-12-11 ((2457368j,0s,0n),+0s,2299161j)> => 
    #  #<BigDecimal:7faef914ff28,'0.2E1',9(27)>, 
    # #<Date: 2015-12-14 ((2457371j,0s,0n),+0s,2299161j) >=> 
    #  #<BigDecimal:7faef914f938,'0.3E1',9(27)>, 
    # #<Date: 2015-12-15 ((2457372j,0s,0n),+0s,2299161j)> => 
    #  #<BigDecimal:7faef914f7a8,'0.4E1',9(27)>, 
    # #<Date: 2015-12-16 ((2457373j,0s,0n),+0s,2299161j)> => 
    #  #<BigDecimal:7faef914f320,'0.5E1',9(27)>, 
    # #<Date: 2015-12-18 ((2457375j,0s,0n),+0s,2299161j)> => 
    #  #<BigDecimal:7faef914e8d0,'0.6E1',9(27)>, 
    # #<Date: 2015-12-21 ((2457378j,0s,0n),+0s,2299161j)> => 
    #  #<BigDecimal:7faef914dde0,'0.7E1',9(27)>, 
    # #<Date: 2016-01-04 ((2457392j,0s,0n),+0s,2299161j)> => 
    #  #<BigDecimal:7faef914dca0,'0.8E1',9(27)>, 
    # #<Date: 2016-01-08 ((2457396j,0s,0n),+0s,2299161j)> => 
    #  #<BigDecimal:7faef914d390,'0.9E1',9(27)>, 
    # #<Date: 2016-01-13 ((2457401j,0s,0n),+0s,2299161j)> => 
    #  0, 
    # #<Date: 2016-01-14 ((2457402j,0s,0n),+0s,2299161j)> => 
    #  0, 
    # #<Date: 2016-03-09 ((2457457j,0s,0n),+0s,2299161j)> => 
    #  #<BigDecimal:7faef914cd28,'0.1E2',9(27)>, 
    # #<Date: 2016-03-15 ((2457463j,0s,0n),+0s,2299161j)> => 
    #  #<BigDecimal:7faef913ff60,'0.11E2',9(27)>, 
    # #<Date: 2016-03-16 ((2457464j,0s,0n),+0s,2299161j)> => 
    #  #<BigDecimal:7faef913f8d0,'0.12E2',9(27)>, 
    # #<Date: 2016-03-21 ((2457469j,0s,0n),+0s,2299161j)> => 
    #  #<BigDecimal:7faef913f560,'0.13E2',9(27)>, 
    # #<Date: 2016-03-22 ((2457470j,0s,0n),+0s,2299161j)> => 
    #  0 
} 

Burada sınıf yöntemleri Date::strptime ve BigDecimal::new kullandım.

Şimdi (aka inject) Hash#reject, Enumerable#group_by, Enumerable#map, Enumerable#reduce ve Array#to_h sonuçları elde etmek için kullanabileceğiniz aya göre

Sum BigDecimal değerler gerektirir:

sums = 
h.reject { |k,_| k.nil? }. 
    group_by { |k,_| [k.year, k.month] }. 
    map { |yr_and_mon, arr| [yr_and_mon, arr.reduce(0) { |t,(_,bd)| t+bd }] }. 
    to_h 
    #=> {[2015, 12]=>#<BigDecimal:7faef9197eb8,'0.28E2',9(18)>, 
    # [2016, 1]=>#<BigDecimal:7faef9197b70,'0.17E2',9(18)>, 
    # [2016, 3]=>#<BigDecimal:7faef9197760,'0.46E2',9(18)>} 

Biz görüyoruz BigDecimal değerleri, tam sayılara dönüştürerek daha kolay okunur:

sums.merge(sums) { |*,v| v.to_i } 
    #=> {[2015, 12]=>28, [2016, 1]=>17, [2016, 3]=>46} 

Bu sonuçları, bu yanıtın başlangıcında hash g ile karşılaştırın.

Her iki karmada birleştirilen anahtarların değerlerini belirlemek için bir blok kullanan Hash#merge formunu kullandım. Kendisiyle sums'u birleştirdiğim için, blok tüm tuşların değerlerini belirlemek için kullanılır.

Karma sums'a sahip olduğunuzda, toplamları istediğiniz herhangi bir biçimde ay ve yıl olarak basmak kolay bir iştir.

biri `dates` anahtarlarının @` nil` olduğu

h1 = h.reject { |k,_| k.nil? }.group_by { |k,_| [k.year, k.month] } 
    #=> {[2015, 12]=>[[#<Date: 2015-12-03 ((2457360j,0s,0n),+0s,2299161j)>, 
    #     #<BigDecimal:7faef915c8e0,'0.1E1',9(27)>], 
    #     [#<Date: 2015-12-11 ((2457368j,0s,0n),+0s,2299161j)>, 
    #     #<BigDecimal:7faef914ff28,'0.2E1',9(27)>], 
    ... 
    #     #<BigDecimal:7faef9093850,'0.46E2',9(18)>]] 
a1 = h1.map { |yr_and_mon, arr| [yr_and_mon, arr.reduce(0) { |t,(_,bd)| t+bd }] } 
    #=> [[[2015, 12], #<BigDecimal:7faef9029dd8,'0.28E2',9(18)>], 
    # [[2016, 1], #<BigDecimal:7faef90296a8,'0.17E2',9(18)>], 
    # [[2016, 3], #<BigDecimal:7faef9028dc0,'0.46E2',9(18)>]] 
a1.to_h 
    #=> {[2015, 12]=>#<BigDecimal:7faef9098710,'0.28E2',9(18)>, 
    # [2016, 1]=>#<BigDecimal:7faef9093da0,'0.17E2',9(18)>, 
    # [2016, 3]=>#<BigDecimal:7faef9093850,'0.46E2',9(18)>} 
İlgili konular