将数组拆分为切片,并进行分组
Split an array into slices, with groupings
我这里有一些 Ruby 代码,可以工作,但我确定我没有尽可能高效地完成它。
我有一个对象数组,沿着这条线:
[
{ name: "foo1", location: "new york" },
{ name: "foo2", location: "new york" },
{ name: "foo3", location: "new york" },
{ name: "bar1", location: "new york" },
{ name: "bar2", location: "new york" },
{ name: "bar3", location: "new york" },
{ name: "baz1", location: "chicago" },
{ name: "baz2", location: "chicago" },
{ name: "baz3", location: "chicago" },
{ name: "quux1", location: "chicago" },
{ name: "quux2", location: "chicago" },
{ name: "quux3", location: "chicago" }
]
我想创建一些组 - 比如 3 - 每个组包含半等量的项目,但穿插 location
。
我试过这样的事情:
group_size = 3
groups = []
group_size.times do
groups.push([])
end
i = 0
objects.each do |object|
groups[i].push(object)
if i < (group_size - 1)
i += 1
else
i = 0
end
end
这个 returns 一个 groups
对象,看起来像:
[
[{:name=>"foo1", :location=>"new york"},
{:name=>"bar1", :location=>"new york"},
{:name=>"baz1", :location=>"chicago"},
{:name=>"quux1", :location=>"chicago"}],
[{:name=>"foo2", :location=>"new york"},
{:name=>"bar2", :location=>"new york"},
{:name=>"baz2", :location=>"chicago"},
{:name=>"quux2", :location=>"chicago"}],
[{:name=>"foo3", :location=>"new york"},
{:name=>"bar3", :location=>"new york"},
{:name=>"baz3", :location=>"chicago"},
{:name=>"quux3", :location=>"chicago"}]
]
因此您可以看到每个分组中的每个位置都有几个对象。
我试过 each_slice()
和 group_by()
,甚至尝试使用 inject([])
- 但我想不出更优雅的方法来做到这一点。
我希望这是我忽略的东西 - 我需要考虑更多 location
和非偶数的对象。
a.each_slice(group_size).to_a.transpose
如果示例中准确描述了您的数据,则可以使用。如果不是,请提供准确的数据,以便我们更恰当地回答问题。
例如
a= [
{ name: "foo1", location: "new york" },
{ name: "foo2", location: "new york" },
{ name: "foo3", location: "new york" },
{ name: "bar1", location: "new york" },
{ name: "bar2", location: "new york" },
{ name: "bar3", location: "new york" },
{ name: "baz1", location: "chicago" },
{ name: "baz2", location: "chicago" },
{ name: "baz3", location: "chicago" },
{ name: "quux1", location: "chicago" },
{ name: "quux2", location: "chicago" },
{ name: "quux3", location: "chicago" }
]
group_size = 3
a.each_slice(group_size).to_a.transpose
#=> [
[
{:name=>"foo1", :location=>"new york"},
{:name=>"bar1", :location=>"new york"},
{:name=>"baz1", :location=>"chicago"},
{:name=>"quux1", :location=>"chicago"}
],
[
{:name=>"foo2", :location=>"new york"},
{:name=>"bar2", :location=>"new york"},
{:name=>"baz2", :location=>"chicago"},
{:name=>"quux2", :location=>"chicago"}
],
[
{:name=>"foo3", :location=>"new york"},
{:name=>"bar3", :location=>"new york"},
{:name=>"baz3", :location=>"chicago"},
{:name=>"quux3", :location=>"chicago"}
]
]
在您的示例中,each_slice
3 会将其分成 4 个相等的组(编号为 1、2、3)。 transpose
然后将这4组变成3组4个。
如果位置不一定按顺序可以在方法链的前面添加排序
a.sort_by { |h| h[:location] }.each_slice(group_size).to_a.transpose
更新
有人指出 transpose
的论点数量是奇数。我的第一个想法是采用@CarySwoveland 的方法,但由于他已经发布了它,所以我想出了一些不同的方法
class Array
def indifferent_transpose
arr = self.map(&:dup)
max = arr.map(&:size).max
arr.each {|a| a.push(*([nil] * (max - a.size)))}
arr.transpose.map(&:compact)
end
end
那么您仍然可以使用相同的方法
a << {name: "foobar1", location: "taiwan" }
a.each_slice(group_size).to_a.indifferent_transpose
#=> [[{:name=>"foo1", :location=>"new york"},
{:name=>"bar1", :location=>"new york"},
{:name=>"baz1", :location=>"chicago"},
{:name=>"quux1", :location=>"chicago"},
#note the extras values will be placed in the group arrays in order
{:name=>"foobar4", :location=>"taiwan"}],
[{:name=>"foo2", :location=>"new york"},
{:name=>"bar2", :location=>"new york"},
{:name=>"baz2", :location=>"chicago"},
{:name=>"quux2", :location=>"chicago"}],
[{:name=>"foo3", :location=>"new york"},
{:name=>"bar3", :location=>"new york"},
{:name=>"baz3", :location=>"chicago"},
{:name=>"quux3", :location=>"chicago"}]]
是的,与 i
的这种记账通常表明应该有更好的东西。我想到了:
ar =[
{ name: "foo1", location: "new york" },
{ name: "foo2", location: "new york" },
{ name: "foo3", location: "new york" },
{ name: "bar1", location: "new york" },
{ name: "bar2", location: "new york" },
{ name: "bar3", location: "new york" },
{ name: "baz1", location: "chicago" },
{ name: "baz2", location: "chicago" },
{ name: "baz3", location: "chicago" },
{ name: "quux1", location: "chicago" },
{ name: "quux2", location: "chicago" },
{ name: "quux3", location: "chicago" }
]
# next line handles unsorted arrays, irrelevant with this data
ar = ar.sort_by{|h| h[:location]}
num_groups = 3
groups = Array.new(num_groups){[]}
wheel = groups.cycle
ar.each{|h| wheel.next << h}
# done.
p groups
# => [[{:name=>"baz1", :location=>"chicago"}, {:name=>"quux1", :location=>"chicago"}, {:name=>"foo1", :location=>"new york"}, ...]
因为我喜欢 cycle 方法。
这是另一种方法。
代码
def group_em(a, ngroups)
a.each_with_index.with_object(Array.new(ngroups) {[]}) {|(e,i),arr|
arr[i%ngroups] << e}
end
例子
a = [
{ name: "foo1", location: "new york" },
{ name: "foo2", location: "new york" },
{ name: "foo3", location: "new york" },
{ name: "bar1", location: "new york" },
{ name: "bar2", location: "new york" },
{ name: "bar3", location: "new york" },
{ name: "baz1", location: "chicago" },
{ name: "baz2", location: "chicago" },
{ name: "baz3", location: "chicago" },
{ name: "quux1", location: "chicago" },
{ name: "quux2", location: "chicago" }
]
请注意,我从问题中省略了 a
的最后一个元素,以便 a
具有奇数个元素。
group_em(a,3)
#=> [[{:name=>"foo1", :location=>"new york"},
# {:name=>"bar1", :location=>"new york"},
# {:name=>"baz1", :location=>"chicago" },
# {:name=>"quux1", :location=>"chicago" }],
# [{:name=>"foo2", :location=>"new york"},
# {:name=>"bar2", :location=>"new york"},
# {:name=>"baz2", :location=>"chicago" },
# {:name=>"quux2", :location=>"chicago" }],
# [{:name=>"foo3", :location=>"new york"},
# {:name=>"bar3", :location=>"new york"},
# {:name=>"baz3", :location=>"chicago" }]]
我这里有一些 Ruby 代码,可以工作,但我确定我没有尽可能高效地完成它。
我有一个对象数组,沿着这条线:
[
{ name: "foo1", location: "new york" },
{ name: "foo2", location: "new york" },
{ name: "foo3", location: "new york" },
{ name: "bar1", location: "new york" },
{ name: "bar2", location: "new york" },
{ name: "bar3", location: "new york" },
{ name: "baz1", location: "chicago" },
{ name: "baz2", location: "chicago" },
{ name: "baz3", location: "chicago" },
{ name: "quux1", location: "chicago" },
{ name: "quux2", location: "chicago" },
{ name: "quux3", location: "chicago" }
]
我想创建一些组 - 比如 3 - 每个组包含半等量的项目,但穿插 location
。
我试过这样的事情:
group_size = 3
groups = []
group_size.times do
groups.push([])
end
i = 0
objects.each do |object|
groups[i].push(object)
if i < (group_size - 1)
i += 1
else
i = 0
end
end
这个 returns 一个 groups
对象,看起来像:
[
[{:name=>"foo1", :location=>"new york"},
{:name=>"bar1", :location=>"new york"},
{:name=>"baz1", :location=>"chicago"},
{:name=>"quux1", :location=>"chicago"}],
[{:name=>"foo2", :location=>"new york"},
{:name=>"bar2", :location=>"new york"},
{:name=>"baz2", :location=>"chicago"},
{:name=>"quux2", :location=>"chicago"}],
[{:name=>"foo3", :location=>"new york"},
{:name=>"bar3", :location=>"new york"},
{:name=>"baz3", :location=>"chicago"},
{:name=>"quux3", :location=>"chicago"}]
]
因此您可以看到每个分组中的每个位置都有几个对象。
我试过 each_slice()
和 group_by()
,甚至尝试使用 inject([])
- 但我想不出更优雅的方法来做到这一点。
我希望这是我忽略的东西 - 我需要考虑更多 location
和非偶数的对象。
a.each_slice(group_size).to_a.transpose
如果示例中准确描述了您的数据,则可以使用。如果不是,请提供准确的数据,以便我们更恰当地回答问题。
例如
a= [
{ name: "foo1", location: "new york" },
{ name: "foo2", location: "new york" },
{ name: "foo3", location: "new york" },
{ name: "bar1", location: "new york" },
{ name: "bar2", location: "new york" },
{ name: "bar3", location: "new york" },
{ name: "baz1", location: "chicago" },
{ name: "baz2", location: "chicago" },
{ name: "baz3", location: "chicago" },
{ name: "quux1", location: "chicago" },
{ name: "quux2", location: "chicago" },
{ name: "quux3", location: "chicago" }
]
group_size = 3
a.each_slice(group_size).to_a.transpose
#=> [
[
{:name=>"foo1", :location=>"new york"},
{:name=>"bar1", :location=>"new york"},
{:name=>"baz1", :location=>"chicago"},
{:name=>"quux1", :location=>"chicago"}
],
[
{:name=>"foo2", :location=>"new york"},
{:name=>"bar2", :location=>"new york"},
{:name=>"baz2", :location=>"chicago"},
{:name=>"quux2", :location=>"chicago"}
],
[
{:name=>"foo3", :location=>"new york"},
{:name=>"bar3", :location=>"new york"},
{:name=>"baz3", :location=>"chicago"},
{:name=>"quux3", :location=>"chicago"}
]
]
在您的示例中,each_slice
3 会将其分成 4 个相等的组(编号为 1、2、3)。 transpose
然后将这4组变成3组4个。
如果位置不一定按顺序可以在方法链的前面添加排序
a.sort_by { |h| h[:location] }.each_slice(group_size).to_a.transpose
更新
有人指出 transpose
的论点数量是奇数。我的第一个想法是采用@CarySwoveland 的方法,但由于他已经发布了它,所以我想出了一些不同的方法
class Array
def indifferent_transpose
arr = self.map(&:dup)
max = arr.map(&:size).max
arr.each {|a| a.push(*([nil] * (max - a.size)))}
arr.transpose.map(&:compact)
end
end
那么您仍然可以使用相同的方法
a << {name: "foobar1", location: "taiwan" }
a.each_slice(group_size).to_a.indifferent_transpose
#=> [[{:name=>"foo1", :location=>"new york"},
{:name=>"bar1", :location=>"new york"},
{:name=>"baz1", :location=>"chicago"},
{:name=>"quux1", :location=>"chicago"},
#note the extras values will be placed in the group arrays in order
{:name=>"foobar4", :location=>"taiwan"}],
[{:name=>"foo2", :location=>"new york"},
{:name=>"bar2", :location=>"new york"},
{:name=>"baz2", :location=>"chicago"},
{:name=>"quux2", :location=>"chicago"}],
[{:name=>"foo3", :location=>"new york"},
{:name=>"bar3", :location=>"new york"},
{:name=>"baz3", :location=>"chicago"},
{:name=>"quux3", :location=>"chicago"}]]
是的,与 i
的这种记账通常表明应该有更好的东西。我想到了:
ar =[
{ name: "foo1", location: "new york" },
{ name: "foo2", location: "new york" },
{ name: "foo3", location: "new york" },
{ name: "bar1", location: "new york" },
{ name: "bar2", location: "new york" },
{ name: "bar3", location: "new york" },
{ name: "baz1", location: "chicago" },
{ name: "baz2", location: "chicago" },
{ name: "baz3", location: "chicago" },
{ name: "quux1", location: "chicago" },
{ name: "quux2", location: "chicago" },
{ name: "quux3", location: "chicago" }
]
# next line handles unsorted arrays, irrelevant with this data
ar = ar.sort_by{|h| h[:location]}
num_groups = 3
groups = Array.new(num_groups){[]}
wheel = groups.cycle
ar.each{|h| wheel.next << h}
# done.
p groups
# => [[{:name=>"baz1", :location=>"chicago"}, {:name=>"quux1", :location=>"chicago"}, {:name=>"foo1", :location=>"new york"}, ...]
因为我喜欢 cycle 方法。
这是另一种方法。
代码
def group_em(a, ngroups)
a.each_with_index.with_object(Array.new(ngroups) {[]}) {|(e,i),arr|
arr[i%ngroups] << e}
end
例子
a = [
{ name: "foo1", location: "new york" },
{ name: "foo2", location: "new york" },
{ name: "foo3", location: "new york" },
{ name: "bar1", location: "new york" },
{ name: "bar2", location: "new york" },
{ name: "bar3", location: "new york" },
{ name: "baz1", location: "chicago" },
{ name: "baz2", location: "chicago" },
{ name: "baz3", location: "chicago" },
{ name: "quux1", location: "chicago" },
{ name: "quux2", location: "chicago" }
]
请注意,我从问题中省略了 a
的最后一个元素,以便 a
具有奇数个元素。
group_em(a,3)
#=> [[{:name=>"foo1", :location=>"new york"},
# {:name=>"bar1", :location=>"new york"},
# {:name=>"baz1", :location=>"chicago" },
# {:name=>"quux1", :location=>"chicago" }],
# [{:name=>"foo2", :location=>"new york"},
# {:name=>"bar2", :location=>"new york"},
# {:name=>"baz2", :location=>"chicago" },
# {:name=>"quux2", :location=>"chicago" }],
# [{:name=>"foo3", :location=>"new york"},
# {:name=>"bar3", :location=>"new york"},
# {:name=>"baz3", :location=>"chicago" }]]