2016-09-20 78 views
2

我是Ruby新手,希望僅對我的集合中的某些項目進行排序。 例如,如果我有以下數組。我只想包含該屬性type: 'sort'對數組中的特定對象進行排序

object = [{ 
      type: 'sort', 
      id: 3 
     }, { 
      type: 'notsort', 
      id: 4 
     }, { 
      type: 'sort', 
      id: 1 
     }, { 
      type: 'sort', 
      id: 0 
     } 
    ] 

我需要爲了直接映射到下面的ID映射的對象進行排序。

sortIdOrder = [0, 1, 3] 

最終的結果應該是這樣的:

object = [{ 
    type: 'notsort', 
    id: 4 
}, { 
    type: 'sort', 
    id: 0 
},{ 
    type: 'sort', 
    id: 1 
}, { 
    type: 'sort', 
    id: 3 
}] 

正如你可以看到陣列由id基礎上,sortIdOrder排序。 notsorttype可以在最後或開始。

+0

作爲說明,約定認爲Ruby方法和變量應該是'sort_id_order'形式。 – tadman

回答

0

一個不是很高性能的一行:

object.sort_by{|o| sortIdOrder.index(o[:id]) || -1} 

這使得notsort對象出現在排序數組的頭。這是一個O(m * nlog(n))算法,其中n的尺寸爲object,而m的尺寸爲sortIdOrder。當您的objectsortIdOrder很小時,這會更快。

更高性能的一個大的陣列是

order = sortIdOrder.each.with_index.with_object(Hash.new(-1)) {|(id, index), h| h[id] = index} 

object.sort_by{|o| order[o[:id]]} 

這是一個O(M + n日誌(n))的算法,但需要更多的存儲器。

0

您可以使用sort,其排序方式爲:type,然後:id

object.sort {|a, b| [a[:type], a[:id]] <=> [b[:type], b[:id]] } 

[{:type=>"notsort", :id=>4}, 
{:type=>"sort", :id=>0}, 
{:type=>"sort", :id=>1}, 
{:type=>"sort", :id=>3}] 
+0

謝謝,但我希望命令由'sortIdOrder'確定。我只需將解決方案更改爲: 'object.sort {| a,b | [a [:type],sortIdOrder.index(a [:id])] <=> [b [:type],sortIdOrder.index(b [:id])]}? – Decrypter

+0

是的,這是有效的。至少在這個例子中。 – davidhu2000

+0

很酷。有些情況下'type'可以是零。在這種情況下這不起作用嗎? – Decrypter

0

我會去像這樣的東西:

object.sort_by do |o| 
    [ 
    (o[:type] == :sort) ? 0 : 1, 
    sortIdOrder.index(o[:id]) 
    ] 
end 

當數組排序,你基本上由第一要素,整理除非它們是相同的,在這種情況下,你按的第二個元素等。在上面的代碼中,(o[:type] == :sort) ? 0 : 1確保一切與類型的:sort至上,一切之後,即使類型爲nil,或5或任何你喜歡。 sortIdOrder.index(o[:id])這個術語可以確保事物按照你喜歡的方式排序(儘管沒有:id:id沒有在sortIdOrder中找到的項目將被任意排序,如果你的數據集非常大,你可能需要進一步調整,以便sortIdOrder數組不對非分類項目執行

Enumerable#sort_by只需對每個元素調用一次塊,然後對結果執行快速比較; Enumerable#sort必須調用塊對元素對,這意味着它被稱爲更多經常:

irb(main):015:0> ary = %w{9 8 7 6 5 4 3 2 1} 
=> ["9", "8", "7", "6", "5", "4", "3", "2", "1"] 
irb(main):016:0> a = 0; ary.sort_by {|x| puts x; a+=1; x.to_i }; puts "Total: #{a}" 
9 
8 
7 
6 
5 
4 
3 
2 
1 
Total: 9 
=> nil 
irb(main):017:0> a = 0; ary.sort {|x,y| puts "#{x},#{y}"; a+=1; x.to_i <=> y.to_i }; puts "Total: #{a}" 
9,5 
5,1 
8,5 
2,5 
7,5 
3,5 
6,5 
4,5 
6,8 
8,9 
7,8 
6,7 
1,3 
3,4 
2,3 
1,2 
Total: 16 
=> nil 

在這些情況下,它並不是很重要,因爲哈希存取速度快反正(雖然sort_by仍然更清晰),但在計算要排序的屬性甚至適度昂貴的情況下,sort_by可以說是相當快一點。如果比較邏輯本身很複雜,則sort的塊形式最爲有用。

+0

謝謝你的回答。如果':type'是零呢? – Decrypter

+0

如果':type'可能爲零,或者除了sort和:nosort之外還有很多不同的類型,並且你想確定除了sort之外的所有東西都被分組在一起,那麼最好使用'[(o [ :type] ==:sort?0:1),sortIdOrder.index(o [:id])'作爲您的排序標準。將所有':sort'放在列表的前面(按照所需的排序順序),然​​後再放入其他所有的東西(如果它們的id在'sortIdOrder'數組中不存在,可能是任意的順序。更新答案以反映這一點。 – philomory

3

排序可能很昂貴,所以不應該在知道所需順序時進行排序,因爲它在這裏。

我假定值:id是唯一的,因爲這個問題是沒有意義的,如果他們不是。

首先將散列劃分成要排序的那些和其餘部分。

sortees, nonsortees = object.partition { |h| h[:type] == 'sort' } 
    #=> [[{:type=>"sort", :id=>3}, {:type=>"sort", :id=>1}, {:type=>"sort", :id=>0}], 
    # [{:type=>"notsort", :id=>4}]] 

所以

sortees 
    #=> [{:type=>"sort", :id=>3}, {:type=>"sort", :id=>1}, {:type=>"sort", :id=>0}] 
nonsortees 
    #=> [{:type=>"notsort", :id=>4}] 

我就把的sortees元件以所需的順序再連接之數組nonsortees,把不屬於在端部要排序的哈希值。

我通過的sortees每個元素g(散列)創建與一個鍵 - 值對g[:id]=>g的散列訂貨的sortees的元素。這允許我使用Hash#values_at以指定的順序提取所需的哈希值。

sortees.each_with_object({}) { |g,h| h[g[:id]] = g }. 
     values_at(*sortIdOrder). 
     concat(nonsortees) 
    #=> [{:type=>"sort", :id=>0}, {:type=>"sort", :id=>1}, {:type=>"sort", :id=>3}, 
    # {:type=>"notsort", :id=>4}] 

注意

sortees.each_with_object({}) { |g,h| h[g[:id]] = g } 
    #=> {3=>{:type=>"sort", :id=>3}, 1=>{:type=>"sort", :id=>1}, 
    # 0=>{:type=>"sort", :id=>0}} 
+0

你知道,帶'index_of'調用的'sort_by'可能是去這裏的路。對於較大的列表,您肯定希望將ID順序數組轉換爲哈希:'Hash [array.each_with_index.to_a] .invert'可以輕鬆完成。 – tadman

+0

@tadman,這是'each_with_index'和'invert'的很好用法。我必須把它甩開。 –

0

也許我來晚了,但我的解決辦法是:

Rails的解決方案:

object.partition { |hash| hash[:id].in?(sortIdOrder) }.flatten.reverse 

紅寶石解決方案:

object.partition { |hash| sortIdOrder.include? hash[:id] }.flatten.reverse 

兩個它的結果給這個:

=> [{:type=>"notsort", :id=>4}, 
    {:type=>"sort", :id=>0}, 
    {:type=>"sort", :id=>1}, 
    {:type=>"sort", :id=>3}] 
相關問題