如何从数组中获取具有条件的数组数组
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
的值可以不是 2014
或 2015
,请将 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}]]
我有一个包含散列的数组,如下所示:
[
{: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
的值可以不是 2014
或 2015
,请将 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}]]