2014-10-11 110 views
4

有人可以告訴我如何基於自定義字符串對嵌套數組進行排序嗎?例如,有沒有辦法排序:使用自定義排序偏好對數組排序?

[['Red','Blue'],['Green','Orange'],['Purple','Yellow']] 

通過"Orange""Yellow",然後"Blue"?最終結果如下所示:

[['Green','Orange'],['Purple','Yellow'],['Red','Blue']] 

它不按字母順序排序。我很想知道是否可以定義值來完成上述目標。

+1

歡迎SO。寫得很好的問題。非常簡潔。 – 2014-10-12 03:44:51

回答

3

這是group_byvalues_at任務:

ORDER = %w[Orange Yellow Blue] 
ary = [['Red','Blue'],['Green','Orange'],['Purple','Yellow']] 

ary.group_by{ |a| a.last }.values_at(*ORDER) 
# => [[["Green", "Orange"]], [["Purple", "Yellow"]], [["Red", "Blue"]]] 

這裏是group_by帶來的一方:

ary.group_by{ |a| a.last } 
# => {"Blue"=>[["Red", "Blue"]], 
#  "Orange"=>[["Green", "Orange"]], 
#  "Yellow"=>[["Purple", "Yellow"]]} 

一旦你有值的用於將每個數組的散列,那麼values_at可以很容易地以正確的順序提取它們。

這是一種非常快速和有效的方式來完成這項任務,因爲它會增加幾乎沒有減慢,因爲沒有真正的排序進行,它只是一個值的分組,然後從哈希中提取以給定的順序。

如果你想完全一樣的陣列的陣列在你的榜樣,flatten結果一次:

ary.group_by{ |a| a.last }.values_at(*ORDER).flatten(1) 
# => [["Green", "Orange"], ["Purple", "Yellow"], ["Red", "Blue"]] 

你不想這樣做,如果有將要多「橙」 ,「黃色」或「藍色」元素作爲結果將不太可用。

+0

感謝這!完善! – LewlSauce 2014-10-11 23:32:15

2

您可以在您的收藏上調用.sort,並傳遞一個知道如何判斷一個元素是否大於另一個的塊。

如果您只是想使用有序的字符串列表來確定哪個字符串比另一個大,那麼您可以定義一個簡單的比較器,它使用排序列表中每個字符串的索引來確定哪個更大。

strs = [['Red','Blue'],['Green','Orange'],['Purple','Yellow']] 

ordering = %w(Orange Yellow Blue) 

p strs.sort { |a,b| ordering.index(a[1]) <=> ordering.index(b[1]) } 

# [["Green", "Orange"], ["Purple", "Yellow"], ["Red", "Blue"]] 
+0

謝謝了。這也有效。 :) 非常感激! – LewlSauce 2014-10-11 23:36:04

7

sort_by始終是那種排序非常方便:

a = [['Red','Blue'],['Green','Orange'],['Purple','Yellow']] 
order_array = ['Orange', 'Yellow', 'Blue'] 

p a.sort_by { |arr| order_array.index(arr[1]) } 

# => [["Green", "Orange"], ["Purple", "Yellow"], ["Red", "Blue"]] 
+0

感謝您的幫助!也爲我工作! – LewlSauce 2014-10-11 23:32:33

0

這裏有一個方法,使「橙色」,「黃」,「藍」是在每個陣列中的任何位置,並且每個數組可能不包含這些三種顏色中的一些或全部。使用給定的字符串排序對每個數組以及包含數組進行排序。正常陣列排序適用,因此,如果每兩個陣列的第一個元素是相同的,所述第二元件相比較,等等

我暫時重新定義String#<=>,然後以通常的方式排序,然後在返回之前恢復String#<=>

代碼

def reorder(arr) 
    String.send(:alias_method, :old_compare, :<=>) 
    String.class_eval do 
    define_method(:<=>) do |other| 
     order = ["Blue", "Yellow", "Orange"] # increasing priority 
     self_ndx = order.index(self) || -1 
     other_ndx = order.index(other) || -1 
     other_ndx <=> self_ndx 
    end 
    end 
    a = arr.map(&:sort).sort 
    String.send(:alias_method, :<=>, :old_compare) 
    String.send(:undef_method, :old_compare) 
    a 
end 

實例

reorder [["Red", "Blue"], ["Green", "Orange"], ["Purple", "Yellow"]] 
    #=> [["Orange", "Green"], ["Yellow", "Purple"], ["Blue", "Red"]] 
reorder [["Blue", "Orange"], ["Purple", "Green"], ["Purple", "Orange"]] 
    #=> [["Orange", "Blue"], ["Orange", "Purple"], ["Purple", "Green"]] 
reorder [["Yellow", "Orange"], ["Orange", "Orange"], ["Blue", "Yellow"]] 
    #=> [["Orange", "Orange"], ["Orange", "Yellow"], ["Yellow", "Blue"]] 
reorder [["Yellow", "Purple"], ["Purple", "Orange", "Blue"], ["Blue", "Yellow"]] 
    #=> [["Orange", "Blue", "Purple"], ["Yellow", "Blue"], ["Yellow", "Purple"]]