2013-07-08 237 views
1

我有散列的數組:如何通過自定義排序順序對數組進行排序?

[{number: 1},{number: 2}, {number: 3}, {number: 4}] 

我需要根據自定義的順序對它們進行排序:

[3,4,1,2] 

因此,其結果應該是:

[{number: 3},{number: 4}, {number: 1}, {number: 2}] 

我知道sort_by存在,但我只用它來升序和降序。

我可以發瘋,不用擔心性能,但是有沒有一種有效的方法來基於通過數組的自定義順序來排序哈希數組?

+0

訂單將如何定義? – lurker

+0

如果我的問題是正確的,它將基於自定義順序,在我上面的示例中,它將從'[2,4,1,3]'工作。我只需要將數字值爲2的第一個散列表作爲第一個,然後是數字值爲4的散列表,等等。 – jason328

+0

將我的答案與Priti的答案進行比較,似乎我們正在解決不同的問題。給定'order = [i,...]',他說「把第一個散列放在第i個位置」。我說「第一個散列應該有數字i」。你在解決哪一個問題? –

回答

5

這取決於如何解釋這個問題,一個潛在的解決方案可能是:

input = [{number: 6},{number: 10}, {number: 2}, {number: 8}] 
hash = Hash[input.map { |h| [h[:number], h] }] 
order = [8,10,6,2] 
output = hash.values_at(*order) 
# => [{:number=>8}, {:number=>10}, {:number=>6}, {:number=>2}] 
+2

'output = hash.values_at(* order)' – tokland

+0

更新爲@ tokland的建議 –

+0

OMG!你也改變了問題上下文:) –

1
input = [{number: 6},{number: 10}, {number: 2}, {number: 8}] 
order = [8,10,6,2] 
order.map{|i| input.find{|h| h[:number] == i }} 
# => [{:number=>8}, {:number=>10}, {:number=>6}, {:number=>2}] 

更新時間短代碼:

input = [{number: 6},{number: 10}, {number: 2}, {number: 8}] 
order = [8,10,6,2] 
input.group_by{|h| h[:number]} 
# => {6=>[{:number=>6}], 
#  10=>[{:number=>10}], 
#  2=>[{:number=>2}], 
#  8=>[{:number=>8}]} 
input.group_by{|h| h[:number]}.values_at(*order) 
# => [[{:number=>8}], [{:number=>10}], [{:number=>6}], [{:number=>2}]] 
+0

謝謝。這是我需要的。 – jason328

+1

使用'shift'對'a'具有破壞性,這可能是不可接受的。使用'find'強制對數組進行重複線性搜索,導致搜索速度越來越慢,因爲'order'或'input'數組越來越多。 –

+0

@theTinMan我刪除了'#shift'版本。 –

1

只是排序的值的索引a

h = [{number: 1},{number: 2}, {number: 3}, {number: 4}] 
a = [3,4,1,2] 

p h.sort_by{|el| a.index(el[:number])} 
# => [{:number=>3}, {:number=>4}, {:number=>1}, {:number=>2}] 
+0

是的,這是一個典型的做法,只有問題是O(n^2)。您可以構建一箇中間散列來使其成爲O(n log n)。 – tokland

+0

@tokland你毫無疑問是正確的,但使用這些數據的速度是[無](http://ideone.com/rDyOG5)中間散列的兩倍。我不知道在這種情況下最好的選擇是什麼。 – steenslag

+0

實際上,對於小輸入,算法的大O通常是不相關的,它只是讀者的注意事項,經常忘記Array#索引是O(n),所以在循環中使用它應該是紅色標誌。 – tokland

相關問題