2014-09-14 3 views
1

Если у меня есть массив объектов, как:Сортировки по индексу в другом массиве

[{id: 1, name: 'Apple'}, 
    {id: 2, name: 'Orange'}, 
    {id: 3, name: 'Banana'}] 

И у меня есть массив идентификаторов: [3, 1, 2]

ли Рубин имеет сжатый и/или эффективный способ сортировать массив по идентификатору во втором массиве как:

[{id: 3, name: 'Banana'}, 
    {id: 1, name: 'Apple'}, 
    {id: 2, name: 'Orange'}] 
+0

@sawa: редактирование только для изменения стиля? Мне нравится это редко ... –

+0

@BorisStitnicky Вы редактировали только, чтобы изменить стиль. Я вернул некоторые ненужные изменения, которые вы сделали. Пожалуйста, не изменяйте стиль OP, особенно от стиля колодца до стиля не образованного человека. Образованный человек не будет помещать пробелы в круглые скобки, скобки или скобки (это прекрасно, чтобы иметь окончания строки). – sawa

+0

@BorisStitnicky Продолжение: (отлично иметь концы строк или отступы). Извините, если это звучит оскорбительно. Я специально не нацеливаюсь на вас. Я знаю, что многие программисты это делают, и меня это раздражает. – sawa

ответ

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])} 
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"}] 

Benchmark

Методы сравниваемых

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 был намного быстрее, чем решение @ Саввы. Я ожидаю, что последний провел большую часть своего времени, выполняя операцию index.

Читатель-претендент: есть много других способов решения этой проблемы. Давайте посмотрим ваши предложения, и я добавлю их в бенчмарк.

+0

+1 от меня. .......... – sawa

Смежные вопросы