Ruby on rails Ruby:将一个数组与另一个数组排序
让o1、o2、o3、o4 activerecord对象 o1.种类=附件2 o2.kind=att3 o3.种类=附件4 o4.kind=att1 设a=[o1,o2,o3,o4] 设b=['att1','att3','att4','att2'] 我需要对a和b进行排序,以便a中的新顺序变成: 我试过了Ruby on rails Ruby:将一个数组与另一个数组排序,ruby-on-rails,ruby,arrays,object,activerecord,Ruby On Rails,Ruby,Arrays,Object,Activerecord,让o1、o2、o3、o4 activerecord对象 o1.种类=附件2 o2.kind=att3 o3.种类=附件4 o4.kind=att1 设a=[o1,o2,o3,o4] 设b=['att1','att3','att4','att2'] 我需要对a和b进行排序,以便a中的新顺序变成: 我试过了 a.sort_by do |element| b.index(element) end 但是如何按种类排序呢?您需要的是element.kind的索引,而不是element 这不使用sor
a.sort_by do |element|
b.index(element)
end
但是如何按种类排序呢?您需要的是element.kind的索引,而不是element
这不使用sort_by,但它会得到您想要的结果。只是用一种不同的方式来思考这个问题
b.map { |att| a.detect { |obj| obj.kind == att } }
在+m上:
我正在使用OpenStruct模拟活动记录结果:
require 'ostruct'
o1, o2, o3, o4 = [*(1..4)].map{ OpenStruct.new }
o1.kind = "att2"
o2.kind = "att3"
o3.kind = "att4"
o4.kind = "att1"
a = [o1, o2, o3, o4]
b = ['att1', 'att3', 'att4', 'att2']
a_hash = Hash[a.map{ |e| [e.kind, e] }]
a_hash # => {"att2"=>#<OpenStruct kind="att2">, "att3"=>#<OpenStruct kind="att3">, "att4"=>#<OpenStruct kind="att4">, "att1"=>#<OpenStruct kind="att1">}
new_a_order = a_hash.values_at(*b)
new_a_order # => [#<OpenStruct kind="att1">, #<OpenStruct kind="att3">, #<OpenStruct kind="att4">, #<OpenStruct kind="att2">]
哪些产出:
Ruby => 2.0.0
N => 1000000
tokland => [#<OpenStruct kind="att1">, #<OpenStruct kind="att3">, #<OpenStruct kind="att4">, #<OpenStruct kind="att2">]
bioneurlanet => [#<OpenStruct kind="att1">, #<OpenStruct kind="att3">, #<OpenStruct kind="att4">, #<OpenStruct kind="att2">]
mihai => [#<OpenStruct kind="att1">, #<OpenStruct kind="att3">, #<OpenStruct kind="att4">, #<OpenStruct kind="att2">]
user system total real
tokland 2.890000 0.010000 2.900000 ( 2.885242)
bioneurlanet 4.430000 0.000000 4.430000 ( 4.434342)
mihai 3.180000 0.010000 3.190000 ( 3.189240)
我将使用哈希而不是数组进行排序:
b = {"att1"=>0, "att3"=>1, "att4"=>2, "att2"=>3}
a.sort_by { |e| b[e.kind] }
这既快又简单
你可以用散列[ary.each_with_index.to_a]b.indexelement.kind?a、b是非常糟糕的名称,即使是举个例子,特别是考虑到它们是集合,所以复数更有意义。请不要这么快选择答案,给人们时间来改进答案。相反,请给出一些反馈。+1表示简单,-1表示在^2上如果这将针对a和/或b的大量值运行,^2上的特性是至关重要的,因为这将导致其运行速度越来越慢。足够公平…好的一点:我更喜欢这种实现,尽管它稍微不那么漂亮,因为它要上映了。@ChrisHeald:这够漂亮吗?a、 mash{o |[o.kind,o]}.value_at*bI只是表示sort_by是自描述性的,而这种形式不太明显,它应该是一种排序。OP想要的不是真正的排序,而是一种关联查找。“不过我想警察不知道。”提曼:说得好。我认为这种关联查找最具声明性的代码可能是一个稍微修改的版本,它使用了一个新的抽象:a.to_hash_by&:kind.values_at*b或类似的东西,categorize_by?。是的,从一开始就使用正确的容器确实有帮助。
require 'ostruct'
o1, o2, o3, o4 = [*(1..4)].map{ OpenStruct.new }
o1.kind = "att2"
o2.kind = "att3"
o3.kind = "att4"
o4.kind = "att1"
a = [o1, o2, o3, o4]
b = ['att1', 'att3', 'att4', 'att2']
a_hash = Hash[a.map{ |e| [e.kind, e] }]
a_hash # => {"att2"=>#<OpenStruct kind="att2">, "att3"=>#<OpenStruct kind="att3">, "att4"=>#<OpenStruct kind="att4">, "att1"=>#<OpenStruct kind="att1">}
new_a_order = a_hash.values_at(*b)
new_a_order # => [#<OpenStruct kind="att1">, #<OpenStruct kind="att3">, #<OpenStruct kind="att4">, #<OpenStruct kind="att2">]
require 'benchmark'
require 'ostruct'
o1, o2, o3, o4 = [*(1..4)].map{ OpenStruct.new }
o1.kind = "att2"
o2.kind = "att3"
o3.kind = "att4"
o4.kind = "att1"
a = [o1, o2, o3, o4]
b = ['att1', 'att3', 'att4', 'att2']
def tokland(a_ary, b_ary)
Hash[a_ary.map{ |e| [e.kind, e] }].values_at(*b_ary)
end
def bioneurlanet(a_ary, b_ary)
b_ary.map { |att| a_ary.detect { |obj| obj.kind == att } }
end
def mihai(a_ary, b_ary)
a_ary.sort_by do |element|
b_ary.index(element.kind)
end
end
N = 1_000_000
puts 'Ruby => ' + RUBY_VERSION
puts 'N => %d' % N
print 'tokland => ', tokland(a,b), "\n"
print 'bioneurlanet => ', bioneurlanet(a,b), "\n"
print 'mihai => ', mihai(a,b), "\n"
Benchmark.bm(12) do |x|
x.report('tokland') { N.times { tokland(a,b) }}
x.report('bioneurlanet') { N.times { bioneurlanet(a,b) }}
x.report('mihai') { N.times { mihai(a,b) }}
end
Ruby => 2.0.0
N => 1000000
tokland => [#<OpenStruct kind="att1">, #<OpenStruct kind="att3">, #<OpenStruct kind="att4">, #<OpenStruct kind="att2">]
bioneurlanet => [#<OpenStruct kind="att1">, #<OpenStruct kind="att3">, #<OpenStruct kind="att4">, #<OpenStruct kind="att2">]
mihai => [#<OpenStruct kind="att1">, #<OpenStruct kind="att3">, #<OpenStruct kind="att4">, #<OpenStruct kind="att2">]
user system total real
tokland 2.890000 0.010000 2.900000 ( 2.885242)
bioneurlanet 4.430000 0.000000 4.430000 ( 4.434342)
mihai 3.180000 0.010000 3.190000 ( 3.189240)
b = {"att1"=>0, "att3"=>1, "att4"=>2, "att2"=>3}
a.sort_by { |e| b[e.kind] }