44

IDの配列があります

a1 = [1, 2, 3, 4, 5]  

ランダムな順序でIDを持つオブジェクトの別の配列があります

a2 = [(obj_with_id_5), (obj_with_id_2), (obj_with_id_1), (obj_with_id_3), (obj_with_id_4)]  

次に、a1のIDの順序に従ってa2を並べ替える必要があります。したがって、a2は次のようになります。

[(obj_with_id_1), (id_2), (id_3), (id_4), (id_5)]  

a1は[3、2、5、4、1]または任意の順序である可能性がありますが、a2はa1のIDの順序に対応している必要があります。

私はこれが好きです:

a1.each_with_index do |id, idx|
  found_idx = a1.find_index { |c| c.id == id }
  replace_elem = a2[found_idx]
  a2[found_idx] = a2[idx]
  a2[idx] = replace_elem
end  

ただし、a2の要素の順序がa1とまったく逆の場合、これはO(n ^ 2)時間に達する可能性があります。誰かがa2をソートする最も効率的な方法を教えてもらえますか?

4

4 に答える 4

86

明白な方法よりもはるかに速いものがあるとしたら、私は驚かれることでしょう。

a2.sort_by{|x| a1.index x.id}
于 2012-08-15T05:04:43.360 に答える
27
hash_object = objects.each_with_object({}) do |obj, hash| 
  hash[obj.object_id] = obj
end

[1, 2, 3, 4, 5].map { |index| hash_object[index] }
#=> array of objects in id's order

実行時間はO(n)になると思います

于 2012-08-14T22:34:32.190 に答える
19

私は受け入れられた答えが好きですが、ActiveSupportには最初のハッシュの作成をさらに簡単にするindex_byがあります。配列からハッシュを作成する最もクリーンな方法を参照してください

実際、Enumerableはindex_byもサポートしているため、これを1行で行うことができます。

a2.index_by(&:id).values_at(*a1)
于 2014-08-13T22:51:08.793 に答える
7

Eric Woodruffの回答に触発されて、私は次のバニラルビーソリューションを思いつきました。

a2.group_by(&:object_id).values_at(*a1).flatten(1)

メソッドのドキュメント:

于 2014-11-07T21:06:55.537 に答える