使用自定义排序首选项排序数组

时间:2014-10-11 23:15:54

标签: ruby

有人可以告诉我如何根据自定义字符串对嵌套数组进行排序吗?例如,有没有办法排序:

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

"Orange""Yellow",然后是"Blue"?最终结果如下:

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

它没有按字母顺序排序。我很想知道我是否可以定义值来排序以实现上述目标。

4 个答案:

答案 0 :(得分:8)

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"]]

答案 1 :(得分: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可以很容易地按正确的顺序提取它们。

这是一种非常快速有效的方法来完成任务,因为随着ary的增长,它几乎没有变慢,因为没有真正的排序,它只是按值分组,然后提取来自给定顺序的哈希。

如果您想要与示例中完全相同的数组数组,flatten结果一次:

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

如果要有多个“橙色”,“黄色”或“蓝色”元素,您将不希望这样做,因为结果将不会非常有用。

答案 2 :(得分: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"]]

答案 3 :(得分: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"]]