2016-09-04 229 views
3

我的数组是这样的:红宝石数组排序

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

如何能不能做到被优化的越好?

回答

1

我的理解是,当a[2] >= 0,排序是到阵列[a[1], a[2]]上,以及其中a[2] < 0将在排序后的数组末尾并按[-a[1], -a[2]]排序的元素。

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

Array#sortEnumerable#sort_by依靠用于确定每一对阵列的顺序进行排序的方法Array#<=>。两个阵列,ab按字典顺序排列,意思如下。如果a[0] < b[0]a小于ba < b)或等效地a <=> b #=> -1。类似地,如果a[0] > b[0]a大于ba > b)和a <=> b #=> 1。如果a[0] == b[0],则通过以相同方式比较第二个元素来打破平局,依此类推。如果a小于ba.size < b.size),并且每个阵列的第一个a.size元素相等,则为a < b。当且仅当a <=> b #=> 0时,ab相等。

由于元素a(其中a[2] < 0将放置在排序数组的末尾),我们需要按排序的数组的第一个元素将数组放在排序数组的前面或后面。正是出于这一原因,我提出的排序由阵列零当a[2] >= 0biggest_plus_1a[2] < 0时,其中biggest_plus_1a[2]最大值加1

所述的其余元件排序由阵列确定的所述第一元件如何对两组数组中的每一组进行排序。

请注意,biggest_plus_1如果全部为a[2] < 0将是非正数,但这并不重要,因为没有元素将按第一个元素为零的数组排序。

+0

非常感谢,它工作得非常好(a [1]> 0,对于错误感到抱歉)。请您解释它是如何工作的,或者给我一个解释语法如何工作的链接? –

+0

非常感谢^^ –

4

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

首先,我们在第三个元素是排序值阳性和/或零:

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

然后我们在第三个元素是负的值进行排序:

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]] 
+0

'sort_by {| ARR | [arr [2],arr [3]]'你能解释它是如何工作的,你应该首先按照arr [2]排序,然后按照arr [3]排序。 ... + 1 – kouty

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返回真,结果会是怎样它:

#=> [[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]] 
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]]