Мой массив выглядит так:
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 ответа
Насколько я понимаю, когда 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 # sort и Enumerable # sort_by полагаются на метод Массив # <=> для определения порядка каждой пары сортируемых массивов. Два массива, a
и b
упорядочены лексикографически, что означает следующее. Если a[0] < b[0]
, то a
меньше, чем b
(a < b
), или, что эквивалентно, a <=> b #=> -1
. Аналогичным образом, если a[0] > b[0]
, то a
больше, чем b
(a > b
) и a <=> b #=> 1
. Если a[0] == b[0]
, связь нарушается путем сравнения вторых элементов таким же образом, и так далее. Если a
меньше, чем b
(a.size < b.size
), и первые a.size
элементы каждого массива равны, a < b
. a
и b
равны тогда и только тогда, когда a <=> b #=> 0
.
Поскольку элементы a
, для которых a[2] < 0
должны быть помещены в конец отсортированного массива, нам необходимо выполнить сортировку по массивам, первые элементы которых помещают массив в начало или в конец отсортированного массива. По этой причине я сделал первый элемент массива сортировки нулем, когда a[2] >= 0
и biggest_plus_1
, когда a[2] < 0
, где biggest_plus_1
- наибольшее значение a[2]
плюс 1.
Остальные элементы массивов сортировки определяют способ сортировки каждой из двух групп массивов.
Обратите внимание, что biggest_plus_1
будет неположительным, если все a[2] < 0
, но это не имеет значения, поскольку ни один элемент не будет отсортирован по массиву, первый элемент которого равен нулю.
Это трехэтапный подход, хотя я уверен, что есть еще один более краткий ответ.
Сначала мы сортируем значения, в которых третий элемент положительный и / или нулевой:
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]]
Сортировка по создает массив и использует его для сортировки значений. Все, что нам нужно сделать, это создать массив, который следует необходимой логике. Для того, чтобы:
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]]
Мой вариант ответа на ваш вопрос:
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]]
Похожие вопросы
Новые вопросы
arrays
Массив - это упорядоченная линейная структура данных, состоящая из набора элементов (значений, переменных или ссылок), каждый из которых идентифицируется одним или несколькими индексами. Когда вы спрашиваете о конкретных вариантах массивов, используйте вместо них следующие связанные теги: [vector], [arraylist], [matrix]. При использовании этого тега в вопросе, относящемся к языку программирования, пометьте вопрос используемым языком программирования.