如果我有一个像这样的对象数组:
[{id: 1, name: 'Apple'},
{id: 2, name: 'Orange'},
{id: 3, name: 'Banana'}]
我有一系列ID:[3, 1, 2]
Ruby是否有一种简洁和/或有效的方法来通过第二个数组中的ID对数组进行排序,如:
[{id: 3, name: 'Banana'},
{id: 1, name: 'Apple'},
{id: 2, name: 'Orange'}]
答案 0 :(得分:3)
可以这样做:
a1 = [{id: 1, name: 'Apple'}, {id: 2, name: 'Orange'}, {id: 3, name: 'Banana'}]
a2 = [3,1,2]
a1.sort_by{|h| a2.index(h[:id])}
答案 1 :(得分:2)
另外两种方式:
<强>#1 强>
def order_hashes1(a,order)
a.each_with_object({}) { |h,g| g.update({h[:id]=>h}) }.values_at(*order)
end
order_hashes1(a1,a2)
#=> [{:id=>3, :name=>"Banana"},
# {:id=>1, :name=>"Apple"},
# {:id=>2, :name=>"Orange"}]
<强>#2 强>
def order_hashes2(a,order)
order.map { |i| a.find { |h| h[:id] == i } }
end
order_hashes2(a1,a2)
#=> [{:id=>3, :name=>"Banana"},
# {:id=>1, :name=>"Apple"},
# {:id=>2, :name=>"Orange"}]
<强>基准强>
方法比较
module Methods
def sawa(a,order)
a.sort_by{ |h| order.index(h[:id]) }
end
def order_hashes1(a,order)
a.each_with_object({}) { |h,g| g.update({h[:id]=>h}) }.values_at(*order)
end
def order_hashes2(a,order)
order.map { |i| a.find { |h| h[:id] == i } }
end
end
include Methods
methods = Methods.instance_methods(false)
#=> [:order_hashes1, :order_hashes2, :sawa]
测试数据
def test_data(n)
a1 = n.times.with_object([]) { |i,a| a << { id: i, name: 'Apple' } }.shuffle
a2 = n.times.to_a.shuffle
[a1, a2]
end
确认所有方法都返回相同的值
a1, a2 = test_data(1_000)
result = send(method.first, a1, a2)
puts methods[1..-1].all? { |m| result = send(m,a1,a2) }
#=> true
基准例程
require 'benchmark'
a1, a2 = test_data(20_000)
Benchmark.bm(methods.map { |m| m.to_s.size }.max) do |bm|
methods.each do |m|
bm.report m.to_s do
send(m, a1, a2)
end
end
end
user system total real
order_hashes1 0.030000 0.000000 0.030000 ( 0.033169)
order_hashes2 49.300000 0.110000 49.410000 ( 49.486159)
sawa 1.500000 0.000000 1.500000 ( 1.499078)
后记
order_hashes2
从未走出大门,我并不感到惊讶,但我惊讶于构建哈希值然后用values_at
提取值比@ sawa的解决方案快得多。我希望后者大部分时间都在执行index
操作。
读者挑战者:还有很多其他方法可以解决这个问题。让我们看看您的建议,然后我们将它们添加到基准测试中。