Ordina un array in base agli elementi di un altro array

Ho una serie di ID

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

e ho un’altra matrice di oggetti con id in ordine casuale

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

Ora ho bisogno di ordinare a2 secondo l’ordine degli id ​​in a1. Quindi a2 dovrebbe ora diventare:

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

a1 potrebbe essere [3, 2, 5, 4, 1] o in qualsiasi ordine ma a2 dovrebbe corrispondere all’ordine degli id ​​in a1.

Mi piace questo:

 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 

Ma questo potrebbe ancora incorrere in un tempo O (n ^ 2) se l’ordine degli elementi di a2 è esattamente al contrario di a1. Qualcuno può dirmi il modo più efficiente di ordinare a2?

 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 

Credo che il tempo di esecuzione sarà O (n)

Sarò sorpreso se qualcosa è molto più veloce del modo ovvio:

 a2.sort_by{|x| a1.index x.id} 

Mi piace la risposta accettata, ma in ActiveSupport c’è index_by che rende ancora più semplice la creazione dell’hash iniziale. Vedi il modo più pulito per creare un hash da una matrice

In effetti, puoi farlo in una riga dal momento che Enumerable supporta anche index_by:

 a2.index_by(&:id).values_at(*a1) 

Ispirato dalla risposta di Eric Woodruff , ho trovato la seguente soluzione di vaniglia Ruby:

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

Documentazione del metodo:

  • Enumerable # group_by
  • Array # values_at
  • Array # appiattiscono