I've got some Ruby code here, that works, but I'm certain I'm not doing it as efficiently as I can.
我这里有一些Ruby代码,可以工作,但是我确信我没有尽可能地高效地完成它。
I have an Array of Objects, along this line:
我有一个对象数组,沿着这条线
[
{ 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" }
]
I want to create some number of groups - say 3 - where each group contains a semi-equal amount of items, but interspersed by location
.
我想要创建一些组(比如3),其中每个组包含半等量的项,但按位置穿插。
I tried something like this:
我试过如下方法:
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
This returns a groups
object, that looks like:
这将返回一个group对象,看起来像:
[
[{: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"}]
]
So you can see there's a couple of objects from each location in each grouping.
你可以看到,每个分组中的每个位置都有几个对象。
I played around with each_slice()
and group_by()
, even tried to use inject([])
- but I couldn't figure out a more elegant method to do this.
我尝试使用each_slice()和group_by(),甚至尝试使用inject([])—但是我想不出一种更优雅的方法。
I'm hoping it's something that I'm overlooking - and I need to account for more location
s and a non-even number of Objects.
我希望这是我忽略的东西——我需要考虑更多的位置和非偶数的对象。
3 个解决方案
#1
4
Yes, this bookkeeping with i
is usually a sign there should be something better. I came up with:
是的,我的这个簿记通常是一个信号,表明应该有更好的东西。我想出了:
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"}, ...]
because I like the cycle method.
因为我喜欢循环法。
#2
3
a.each_slice(group_size).to_a.transpose
a.each_slice .to_a.transpose(group_size)
Will work given that your data is accurately portrayed in the example. If it is not please supply accurate data so that we can answer the question more appropriately.
如果您的数据在示例中被准确地描绘出来,将会工作。如果不是,请提供准确的数据,以便我们能更恰当地回答问题。
e.g.
如。
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 will turn this into 4 equal groups (numbered 1,2,3) in your example. transpose
will then turn these 4 groups into 3 groups of 4.
在示例中,each_slice 3将把它变成4个相等的组(编号为1、2、3)。转置将这4个组变成3组4。
If the locations are not necessarily in order you can add sorting to the front of the method chain
如果位置不一定按顺序排列,可以将排序添加到方法链的前面
a.sort_by { |h| h[:location] }.each_slice(group_size).to_a.transpose
Update
更新
It was pointed out that an uneven number of arguments for transpose
will raise. My first though was to go with @CarySwoveland's approach but since he already posted it I came up with something a little different
指出了转置的参量不均匀会增加。我的第一个想法是使用@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
then you can still use the same methodology
然后你仍然可以使用相同的方法
a << {name: "foobar1", location: "*" }
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=>"*"}],
[{: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"}]]
#3
2
Here's another way to do it.
这是另一种方法。
Code
代码
def group_em(a, ngroups)
a.each_with_index.with_object(Array.new(ngroups) {[]}) {|(e,i),arr|
arr[i%ngroups] << e}
end
Example
例子
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" }
]
Note that I've omitted the last element of a
from the question in order for a
to have an odd number of elements.
注意,我省略了问题中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" }]]
#1
4
Yes, this bookkeeping with i
is usually a sign there should be something better. I came up with:
是的,我的这个簿记通常是一个信号,表明应该有更好的东西。我想出了:
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"}, ...]
because I like the cycle method.
因为我喜欢循环法。
#2
3
a.each_slice(group_size).to_a.transpose
a.each_slice .to_a.transpose(group_size)
Will work given that your data is accurately portrayed in the example. If it is not please supply accurate data so that we can answer the question more appropriately.
如果您的数据在示例中被准确地描绘出来,将会工作。如果不是,请提供准确的数据,以便我们能更恰当地回答问题。
e.g.
如。
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 will turn this into 4 equal groups (numbered 1,2,3) in your example. transpose
will then turn these 4 groups into 3 groups of 4.
在示例中,each_slice 3将把它变成4个相等的组(编号为1、2、3)。转置将这4个组变成3组4。
If the locations are not necessarily in order you can add sorting to the front of the method chain
如果位置不一定按顺序排列,可以将排序添加到方法链的前面
a.sort_by { |h| h[:location] }.each_slice(group_size).to_a.transpose
Update
更新
It was pointed out that an uneven number of arguments for transpose
will raise. My first though was to go with @CarySwoveland's approach but since he already posted it I came up with something a little different
指出了转置的参量不均匀会增加。我的第一个想法是使用@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
then you can still use the same methodology
然后你仍然可以使用相同的方法
a << {name: "foobar1", location: "*" }
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=>"*"}],
[{: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"}]]
#3
2
Here's another way to do it.
这是另一种方法。
Code
代码
def group_em(a, ngroups)
a.each_with_index.with_object(Array.new(ngroups) {[]}) {|(e,i),arr|
arr[i%ngroups] << e}
end
Example
例子
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" }
]
Note that I've omitted the last element of a
from the question in order for a
to have an odd number of elements.
注意,我省略了问题中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" }]]