Ruby 如何从数组中获取具有条件的数组数组

Ruby 如何从数组中获取具有条件的数组数组,ruby,arrays,hash,Ruby,Arrays,Hash,我有一个包含散列的数组,如下所示: [ {:id => 1, :week => 1, :year => 2014}, {:id => 2, :week => 2, :year => 2014}, {:id => 1, :week => 1, :year => 2015}, {:id => 2, :week => 5, :year => 2015}, ] 我需要的是一个数组数组,每个数组包含两

我有一个包含散列的数组,如下所示:

[
    {:id => 1, :week => 1, :year => 2014},
    {:id => 2, :week => 2, :year => 2014},
    {:id => 1, :week => 1, :year => 2015},
    {:id => 2, :week => 5, :year => 2015},
]
我需要的是一个数组数组,每个数组包含两个值: 第一个值是来自2014年第一个数组的哈希,第二个值是来自2015年第一个数组的哈希,如果它与第一个哈希具有相同的周和id

如果从2015年起没有id和week相等的散列,则第二个值必须为零,反之亦然,第一个值为零

对于上面的数组,新数组应该如下所示:

[
    [{:id => 1, :week => 1, :year => 2014}, {:id => 1, :week => 1, :year => 2015}],
    [{:id => 2, :week => 2, :year => 2014}, nil],
    [nil, {:id => 2, :week => 5, :year => 2015}],
]
-e- 我的做法:

result = []
all_ids.each do |id|
  all_weeks.each do |week|
    v1 = array.select{ |v| v.id == id && v.week == week && v.year == 2014}        
    v2 = array.select{ |v| v.id == id && v.week == week && v.year == 2015}
    v1 = v1.length == 1 ? v1.first : nil
    v2 = v2.length == 1 ? v1.first : nil
    result << [v1, v2]
  end

end
result=[]
所有| id。每个都有| id|
每个星期都做|
v1=数组。选择{v | v.id==id&&v.week==week&&v.year==2014}
v2=数组。选择{v | v.id==id&&v.week==week&&v.year==2015}
v1=v1.length==1?v1.1:零
v2=v2.length==1?v1.1:零

结果使用
group_by
按周和id分隔散列,然后只需填充没有两个值的数组:

array.group_by { |v| [v[:id], v[:week]] }.values.each do |a|
  a.insert(2015 - a[0][:year], nil) if a.length == 1
end

这里有一种强调可读性的方法(认真地)

代码

    def convert(arr)
      a14 = arr.select { |h| h[:year] == 2014 }
      a15 = arr - a14
      arr = a14.map do |h14|
        i15 = a15.index { |h15| h14[:id]==h15[:id] && h14[:week]==h15[:week] }
        [ h14, i15.nil? ? nil : a15.delete_at(i15) ]
      end
      arr.concat([nil].product(a15)) if a15.any?
    end
arr = [ {:id => 1, :week => 1, :year => 2014},
        {:id => 2, :week => 2, :year => 2014},
        {:id => 1, :week => 1, :year => 2015},
        {:id => 2, :week => 5, :year => 2015} ]

convert(arr)
  #=> [[{:id=>1, :week=>1, :year=>2014}, {:id=>1, :week=>1, :year=>2015}],
  #    [{:id=>2, :week=>2, :year=>2014}, nil],
  #    [nil, {:id=>2, :week=>5, :year=>2015}]] 
如果
:year
的值可能不是
2014
2015
,则将
a15=arr-a14
替换为:

a15 = arr.select { |h| h[:year] == 2015 }
请注意,
a15.delete_at(i15)
具有双重功能:它从
a15
中删除索引
i15
处的值,并返回该值以包含在元组中

示例

    def convert(arr)
      a14 = arr.select { |h| h[:year] == 2014 }
      a15 = arr - a14
      arr = a14.map do |h14|
        i15 = a15.index { |h15| h14[:id]==h15[:id] && h14[:week]==h15[:week] }
        [ h14, i15.nil? ? nil : a15.delete_at(i15) ]
      end
      arr.concat([nil].product(a15)) if a15.any?
    end
arr = [ {:id => 1, :week => 1, :year => 2014},
        {:id => 2, :week => 2, :year => 2014},
        {:id => 1, :week => 1, :year => 2015},
        {:id => 2, :week => 5, :year => 2015} ]

convert(arr)
  #=> [[{:id=>1, :week=>1, :year=>2014}, {:id=>1, :week=>1, :year=>2015}],
  #    [{:id=>2, :week=>2, :year=>2014}, nil],
  #    [nil, {:id=>2, :week=>5, :year=>2015}]] 

我更新了问题
a.groupu的{| el |[el[:id],el[:week]}
可能是一个好方法。