Ruby on rails Ruby:将一个数组与另一个数组排序

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

让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

这不使用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] }