根据另一个数组元素的类对数组进行排序

时间:2018-09-28 08:26:41

标签: arrays ruby hash

我正在寻找一种方法,可以根据另一个数组中元素的类别对数组中的元素进行排序。我有:

order = [String, Integer, NilClass ,TrueClass]
arry = [1, 2, 3, 4, 5, true, false, nil, 34, nil, 'Hello', 'World']

order中,元素的顺序是动态的。结果应该是:

result_arry = ['Hello', 'World', 1, 2, 3, 4, 5, 34, nil, nil, true, false]

如何根据arry中元素的类别对order进行排序?

我尝试过:

hash = arry.group_by  {|n| n.class } 
# => {Fixnum=>[1, 2, 3, 4, 5, 34], TrueClass=>[true], FalseClass=>[false], NilClass=>[nil, nil], String=>["Hello", "World"]}

3 个答案:

答案 0 :(得分:4)

使用group_by是一个好方法,因为它可以保持元素的顺序:

hash = arry.group_by(&:class)
#=> {
#     Integer => [1, 2, 3, 4, 5, 34],
#     TrueClass => [true],
#     FalseClass => [false],
#     NilClass => [nil, nil],
#     String => ["Hello", "World"]
#   }

我们可以使用sort_by根据order数组中每个键的index对哈希进行排序。如果orders中缺少类,我们将使用数组的size作为后备,以使其最后排序:

sorted = hash.sort_by { |k, _| order.index(k) || order.size }
#=> [
#     [String, ["Hello", "World"]],
#     [Integer, [1, 2, 3, 4, 5, 34]],
#     [NilClass, [nil, nil]],
#     [TrueClass, [true]],
#     [FalseClass, [false]]
#  ]

最后,flat_map提取每个元素的last部分:

sorted.flat_map(&:last)
#=> ["Hello", "World", 1, 2, 3, 4, 5, 34, nil, nil, true, false]

您也可以不经事先分组就使用sort_by,但可能会洗改具有相同类的元素:

arry.sort_by { |e| order.index(e.class) || order.size }
#=> ["World", "Hello", 3, 4, 5, 1, 2, 34, nil, nil, true, false]

这是因为sort_by不稳定。

为了修复它,我们必须考虑它们的索引:

arry.sort_by.with_index { |e, i| [order.index(e.class) || order.size, i] }
#=> ["Hello", "World", 1, 2, 3, 4, 5, 34, nil, nil, true, false]

如果您还想匹配子类(例如,使旧版本的Ruby版本中的IntegerFixnum匹配,则必须将一个块传递给index

order.index { |cls| e.is_a?(cls) }

答案 1 :(得分:3)

我认为这可行:

T Data

arry.sort_by{ |v| order.map{ |c| v.is_a?(Object.const_get(c)) ? -1 : 1 } } # ["Hello", "World", 1, 2, 3, 4, 5, 34, nil, nil, true, false] 将字符串转换为类。

答案 2 :(得分:1)

排序,本身是不必要的。

missing_classes = arry.map(&:class) - order
  #=> [Symbol, FalseClass]
arry.group_by(&:class).values_at(*(order + missing_classes)).flatten
  #=> ["Hello", "World", 1, 2, 3, 4, 5, 34, nil, nil, true, :cat, false]