2012-08-14 59 views
31

我有ID排序根據

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

的陣列,並且我有目的的另一陣列IDS按隨機順序另一個陣列的元件的陣列

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

現在我需要排序a2根據a1中的id的順序。所以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 

但是,這仍然可能會遇到一個爲O(n^2)時間,如果A2的元素的順序完全顛倒A1的。有人可以告訴我排序A2最有效的方法嗎?

回答

23
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)的

+1

我相信這將是爲O(n^2)。實際的排序是O(n),但是準備步驟會使它n^2 – Jato 2012-08-15 05:34:23

+1

我不同意,建立哈希表需要O(n),看這裏http://en.wikipedia.org/wiki/ Hash_table – megas 2012-08-15 05:49:11

+1

是的,構建哈希表是O(n)時間。排序是O(n)時間。所以你有2xO(n)...嗯...那會少於n^2。我立場糾正。接得好! – Jato 2012-08-15 13:41:28

56

,我會感到驚訝,如果有什麼比明顯的方法要快得多:

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

假設a1被排序(並且它來自問題stmt),並且你用於a1的容器可以利用a1排序的事實,那麼我認爲這將比O(n^2)更快。 – Jato 2012-08-15 05:36:45

+1

沒有a1被排序不是一個優勢,我不知道你爲什麼會這麼想。這種方式很快,因爲它是內置的。試圖擊敗內置的sort_by對我來說似乎浪費時間。正在排序的 – pguardiario 2012-08-15 06:24:51

+0

a1是一個優勢。如果它被排序,那麼索引操作應該在O(log n)時間內運行(假設二進制搜索),並且如果它沒有排序,索引將在O(n)時間運行。 – Jato 2012-08-15 13:38:42

14

我喜歡接受的答案,但在ActiveSupport中有index_by,這使得更容易創建初始散列。見Cleanest way to create a Hash from an Array

事實上,你可以在一行中做到這一點,因爲可枚舉index_by支持,以及:

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

這隻適用於您的原始列表中沒有任何重複項目的情況。索引將覆蓋任何重複的ID。這對你來說可能是也可能不是問題。 – Josh 2016-02-04 20:20:23

5

通過Eric Woodruff's Answer啓發,我想出了以下香草紅寶石解決方案:

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

方法文件:

+0

我最喜歡這個解決方案。它很高效(我懷疑它比@ pguardiario的解決方案更有效),而且重要的是,允許'a2'的兩個元素對「id」具有相同的值。這個問題沒有說明這個ID是唯一的,但是一些答案,包括所選的一個,取決於這個ID是唯一的。 – 2017-10-08 18:07:07