2013-07-08 197 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

相关问题