集团红宝石阵由月和年日期成散列 [英] Group a Ruby Array of Dates by Month and Year into a Hash

查看:113
本文介绍了集团红宝石阵由月和年日期成散列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

比方说,我有日期的红宝石阵就像:

  2011-01-20
2011-01-23
2011-02-01
2011-02-15
2011-03-21

什么是创建一个哈希的一个简单和红宝石去年秋季的方式,组逐年日期元素,然后一个月,如:

  {
    2011 => {
        1 => [2011-01-20,2011-01-23]
        2 => [2011-02-01,2011-02-15]
        3 => [2011-03-21]
    }
}

我可以通过遍历一切,提取年,月等等,那么他们comining做到这一点。

红宝石提供了数组和哈希这么多的方法和块,必须有一个更简单的方法?


解决方案

 要求'日期'日期= [
  '2011-01-20',
  '2011-01-23',
  '2011-02-01',
  '2011-02-15',
  '2011-03-21'
] .MAP {| SD | Date.parse(SD)}哈希[
  dates.group_by(安培;:年).MAP {| Y,物品|
    [Y,items.group_by {| D | d.strftime('%B')}]
  }
]
#=> {2011 => {一月=>#<日期:2011-01-20(4911163 / 2,0,2299161)>中#<日期:2011-01-23(二分之四百九十一万一千一百六十九, 0,2299161)]的计算值,二​​月= GT;#<日期:2011-02-01(4911187 / 2,0,2299161)>中#<日期:2011-02-15(4911215 / 2,0,2299161)]的计算值,三八=>#<日期:2011-03-21(4911283 / 2,0,2299161)GT;]}}

我注意到你已经改变月份名称为数字,所以你可能要替换 d.strftime(%B')上面 D .month 或任何其他。

下面是一个一步一步的解释是:

您想基本上两个级别的分组:由今年第一级,第二次由一个月。 Ruby有非常有用的方法 GROUP_BY ,这组由下式给出前pression(块)的元素。所以:第一部分是由一年分组原始数组

  hash_by_year = dates.group_by(安培;:年)
#=> {2011 =>#<日期:2011-01-20(4911163 / 2,0,2299161)>中#<日期:2011-01-23(4911169 / 2,0,2299161)>中#<日期:2011-02-01(4911187 / 2,0,2299161)>中#<日期:2011-02-15(4911215 / 2,0,2299161)>中#<日期:2011 -03-21(4911283 / 2,0,2299161)GT;]}

这给了我们第一个层次:键年,重视与特定年份日期的数组。但是,我们仍然需要组第二级:这就是为什么我们通过映射今年哈希 - 通过其值组。让我们为开始忘记的strftime ,并说,我们被分组 d.month

  hash_by_year.map {|一年,dates_in_year |
  【同期,dates_in_year.group_by(安培;:月)]
}
#=> [[2011年,{1 = GT;#<日期:2011-01-20(4911163 / 2,0,2299161)>中#<日期:2011-01-23(4911169 / 2,0,2299161 )]的计算值,2 =>#<日期:2011-02-01(4911187 / 2,0,2299161)>中#<日期:2011-02-15(4911215 / 2,0,2299161 )]的计算值,3 => [#&下;日期:2011-03-21(4911283 / 2,0,2299161)]的计算值}]]

这样,我们得到了我们的第二个层次分组。相反,在一年的所有日期的数组,现在我们有哈希键均为个月,和值日期的阵列对于给定的月份。

我们唯一的问题是,地图返回一个数组,而不是一个哈希值。这就是为什么我们的包围整前pression 哈希[] ,这使得散列出双阵列,在我们的例子中对 [同期,hash_of_dates_by_month]

很抱歉,如果解释听起来很混乱,我发现了难以解释的功能前pressions不是必要的,因为嵌套。 (

Let's say I had a Ruby Array of Dates like:

2011-01-20
2011-01-23
2011-02-01
2011-02-15
2011-03-21

What would be an easy and Ruby-esque way of creating a Hash that groups the Date elements by year and then month, like:

{
    2011 => {
        1   => [2011-01-20, 2011-01-23],
        2   => [2011-02-01, 2011-02-15],
        3  => [2011-03-21],
    }
}

I can do this by iterating over everything and extracting years, months and so on, then comining them.

Ruby offers so many methods and blocks for Arrays and Hashes, there must be an easier way?

解决方案

require 'date'

dates = [
  '2011-01-20',
  '2011-01-23',
  '2011-02-01',
  '2011-02-15',
  '2011-03-21'
].map{|sd| Date.parse(sd)}

Hash[
  dates.group_by(&:year).map{|y, items|
    [y, items.group_by{|d| d.strftime('%B')}]
  }
]
#=> {2011=>{"January"=>[#<Date: 2011-01-20 (4911163/2,0,2299161)>, #<Date: 2011-01-23 (4911169/2,0,2299161)>], "February"=>[#<Date: 2011-02-01 (4911187/2,0,2299161)>, #<Date: 2011-02-15 (4911215/2,0,2299161)>], "March"=>[#<Date: 2011-03-21 (4911283/2,0,2299161)>]}} 

I noticed you have changed month names into numbers, so you may want to replace d.strftime('%B') above with d.month or whatever else.

Here's a step-by-step explanation:

You essentially want two-level grouping: first level by year, second by month. Ruby has very useful method group_by, which groups elements by given expression (a block). So: first part is grouping original array by year:

hash_by_year = dates.group_by(&:year)
# => {2011=>[#<Date: 2011-01-20 (4911163/2,0,2299161)>, #<Date: 2011-01-23 (4911169/2,0,2299161)>, #<Date: 2011-02-01 (4911187/2,0,2299161)>, #<Date: 2011-02-15 (4911215/2,0,2299161)>, #<Date: 2011-03-21 (4911283/2,0,2299161)>]}

That gives us first level: keys are years, values arrays of dates with given year. But we still need to group the second level: that's why we map by-year hash - to group its values by month. Let's for start forget strftime and say that we're grouping by d.month:

hash_by_year.map{|year, dates_in_year|
  [year, dates_in_year.group_by(&:month)]
}
# => [[2011, {1=>[#<Date: 2011-01-20 (4911163/2,0,2299161)>, #<Date: 2011-01-23 (4911169/2,0,2299161)>], 2=>[#<Date: 2011-02-01 (4911187/2,0,2299161)>, #<Date: 2011-02-15 (4911215/2,0,2299161)>], 3=>[#<Date: 2011-03-21 (4911283/2,0,2299161)>]}]]

That way we got our second level grouping. Instead of array of all dates in a year, now we have hash whose keys are months, and values arrays of dates for a given month.

The only problem we have is that map returns an array and not a hash. Thats why we "surround" whole expression by Hash[], which makes a hash out of array of pairs, in our case pairs [year, hash_of_dates_by_month].

Sorry if the explanation sounds confusing, I found harder to explain functional expressions than imperative, because of the nesting. :(

这篇关于集团红宝石阵由月和年日期成散列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆