Ruby根据多个条件对数字数组进行排序

时间:2016-09-04 20:38:13

标签: arrays ruby sorting

我的数组看起来像这样:

to_sort = [[1, 27, -3, 1.0], [2, 27, -2, 2.0], [3, 27, -2, 3.0], [4, 27, -2, 4.0],
           [5, 27, -2, 5.0], [6, 27, 1, 11.0], [7, 27, 1, 12.0], [8, 27, 1, 13.0],
           [9, 27, 2, 14.0]]

我想根据它们的第二个和第三个值按升序对这些数组进行排序,但是对于第三个数字具有负数的数组必须逐渐排序并放在其他数组之后。
结果应该是这样的:

sorted = [[6, 27, 1, 11.0], [7, 27, 1, 12.0], [8, 27, 1, 13.0], [9, 27, 2, 14.0],
          [2, 27, -2, 2.0], [3, 27, -2, 3.0], [4, 27, -2, 4.0], [5, 27, -2, 5.0],
          [1, 27, -3, 1.0]]

如何做到尽可能优化?

4 个答案:

答案 0 :(得分:4)

这是一个三步法,但我确信还有另一个更简洁的答案。

首先,我们对第3个元素为正和/或零的值进行排序:

pos = to_sort.select { |arr| arr[2] >= 0 }.sort_by { |arr| [arr[2], arr[3]] }
=> [[6, 27, 1, 11.0], [7, 27, 1, 12.0], [8, 27, 1, 13.0], [9, 27, 2, 14.0]]

然后我们对第3个元素为负数的值进行排序:

neg = to_sort.select { |arr| arr[2] < 0 }.sort_by { |arr| [-arr[2], arr[3]] }

然后我们将它们组合在一起:

pos + neg
=> [[6, 27, 1, 11.0],
 [7, 27, 1, 12.0],
 [8, 27, 1, 13.0],
 [9, 27, 2, 14.0],
 [2, 27, -2, 2.0],
 [3, 27, -2, 3.0],
 [4, 27, -2, 4.0],
 [5, 27, -2, 5.0],
 [1, 27, -3, 1.0]]

答案 1 :(得分:1)

我的理解是,当a[2] >= 0时,对数组[a[1], a[2]]进行排序,并且a[2] < 0将在排序数组的末尾进行排序,并按{{排序1}}。

[-a[1], -a[2]]

Array#sortEnumerable#sort_by依赖方法Array#<=>来确定要排序的每对数组的顺序。两个数组biggest_plus_1 = to_sort.map { |a| a[2] }.max + 1 #=> 3 to_sort.sort_by { |a| a[2] >= 0 ? [0, a[1], a[2]] : [biggest_plus_1, -a[1], -a[2]] } #=> [[6, 27, 1, 11.0], [7, 27, 1, 12.0], [8, 27, 1, 13.0], [9, 27, 2, 14.0], # [5, 27, -2, 5.0], [2, 27, -2, 2.0], [3, 27, -2, 3.0], [4, 27, -2, 4.0], # [1, 27, -3, 1.0]] a按字典顺序排列,表示以下内容。如果ba[0] < b[0]小于ab),或等效a < b。同样,如果a <=> b #=> -1a[0] > b[0]大于ab)和a > b。如果a <=> b #=> 1,则通过以相同方式比较第二个元素来打破平局,依此类推。如果a[0] == b[0]小于ab),并且每个数组的第一个a.size < b.size元素相等,则a.size。当且仅当a < b

时,ab相等

由于要将a <=> b #=> 0放置在排序数组末尾的元素a,我们需要按数组排序,这些数组的第一个元素将数组放在排序数组的前面或后面。出于这个原因,我在a[2] < 0a[2] >= 0 biggest_plus_1时将排序依据数组的第一个元素设为零,其中a[2] < 0是{{}的最大值1}}加1。

sort-by数组的其余元素确定如何对两组数组中的每一个进行排序。

请注意,biggest_plus_1如果全部为a[2],则为非正数,但无关紧要,因为没有元素将按第一个元素为零的数组排序。

答案 2 :(得分:1)

我的问题的变体是:

to_sort.sort_by { |a| a[1].abs; a[2] < 0 ? a[2].abs+1 : a[2] }
#=>[[6, 27, 1, 11.0], [7, 27, 1, 12.0], [8, 27, 1, 13.0], [9, 27, 2, 14.0],
# [2, 27, -2, 2.0], [3, 27, -2, 3.0], [4, 27, -2, 4.0], [5, 27, -2, 5.0],
# [1, 27, -3, 1.0]]

另外,我们只能使用.abs,它看起来像:

to_sort.sort_by { |a| a[1].abs; a[2].abs } 

但是这样-2 == 2返回true,结果就像它一样:

#=> [[6, 27, 1, 11.0], [7, 27, 1, 12.0], [8, 27, 1, 13.0], [2, 27, -2, 2.0],
# [3, 27, -2, 3.0], [4, 27, -2, 4.0], [5, 27, -2, 5.0], [9, 27, 2, 14.0],
# [1, 27, -3, 1.0]]

答案 3 :(得分:1)

按创建和数组排序,并使用它对值进行排序。 我们所需要做的就是创建一个遵循所需逻辑的数组。按顺序:

to_sort.sort_by do |array|
  [
    array[2] > 0 ? -1 : 1,  # Put all non-negative numbers of ix 2 first.
    array[2].abs,           # Sort by absolute value of ix 2.
    array[3]                # Then sort using ix 3.
  ]
}

结果:

#=> [[6, 27, 1, 11.0], [7, 27, 1, 12.0], [8, 27, 1, 13.0], [9, 27, 2, 14.0], [2, 27, -2, 2.0], [3, 27, -2, 3.0], [4, 27, -2, 4.0], [5, 27, -2, 5.0], [1, 27, -3, 1.0]]