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

How to get array of arrays with conditions from an array

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

[
    {: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 和周数的哈希值,则第二个值必须为 nil,反之第一个值为 nil。

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

[
    [{: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

这似乎不是很有效,因为我必须多次迭代数组

使用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

如果 :year 的值可以不是 20142015,请将 a15 = arr - a14 替换为:

a15 = arr.select { |h| h[:year] == 2015 }

请注意 a15.delete_at(i15) 具有双重功能:它从 a15 和 returns 中删除索引 i15 处的值以包含在元组中。

例子

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}]]