2

o1, o2, o3, o4activerecord 对象与

  • o1.kind = "att2"
  • o2.kind = "att3"
  • o3.kind = "att4"
  • o4.kind = "att1"

a = [o1, o2, o3, o4]

b = ['att1', 'att3', 'att4', 'att2']

我需要排序ab以便新顺序a变为:

a = [o4, o2, o3, o1]

我试过了

a.sort_by do |element|
  b.index(element)
end

但是如何排序kind?

4

5 回答 5

6

您需要 的索引element.kind,而不是element

a.sort_by do |element|
  b.index(element.kind)
end
于 2013-08-01T15:14:47.877 回答
4

O(n+m):

Hash[a.map { |o| [o.kind, o] }].values_at(*b)
于 2013-08-01T15:36:16.800 回答
4

我正在使用 OpenStruct 来模仿 Active Record 结果:

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)
于 2013-08-01T15:37:23.137 回答
2

这不使用sort_by,但它会得到你想要的结果。只是换一种方式来思考这个问题。

b.map { |att| a.detect { |obj| obj.kind == att } }
于 2013-08-01T15:22:13.573 回答
1

我会使用哈希而不是数组进行排序:

b = {"att1"=>0, "att3"=>1, "att4"=>2, "att2"=>3}
a.sort_by { |e| b[e.kind] }

这既快速又简单。

您可以使用转换现有数组Hash[ary.each_with_index.to_a]

于 2013-08-01T17:08:50.797 回答