2014-10-11 102 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"]]