Ответ 1
Как насчет:
ordered_list = [[1, "b"], [1, "a"], [2, "a"]]
ordered_list.sort! do |a,b|
[a[0],b[1]] <=> [b[0], a[1]]
end
Мне бы очень хотелось справиться с этим без патчей обезьян, но я еще не смог найти еще один вариант.
У меня есть массив (в Ruby), который мне нужно отсортировать по нескольким условиям. Я знаю, как использовать метод сортировки, и я использовал трюк при сортировке, используя массив параметров для сортировки по нескольким условиям. Однако в этом случае мне нужно, чтобы первое условие сортировалось по возрастанию, а второе сортировалось по убыванию. Например:
ordered_list = [[1, 2], [1, 1], [2, 1]]
Любые предложения?
Редактирование: только что я понял, что я не могу легко сравнить первое и второе значения (я на самом деле работаю с атрибутами объекта здесь). Поэтому для простого примера это больше похоже на:
ordered_list = [[1, "b"], [1, "a"], [2, "a"]]
Как насчет:
ordered_list = [[1, "b"], [1, "a"], [2, "a"]]
ordered_list.sort! do |a,b|
[a[0],b[1]] <=> [b[0], a[1]]
end
У меня был кошмар времени, пытаясь понять, как отменить сортировку определенного атрибута, но обычно сортировать два других. Просто примечание о сортировке для тех, кто приходит после этого и смущен | a, b | синтаксис блока. Вы не можете использовать стиль блока {|a,b| a.blah <=> b.blah}
с sort_by!
или sort_by
. Он должен использоваться с sort!
или sort
. Кроме того, как показано ранее другими плакатами, замените a
и b
на оператор сравнения <=>
, чтобы отменить порядок сортировки. Вот так:
Сортировать по blah и craw обычно, но сортировать по bleu в обратном порядке:
something.sort!{|a,b| [a.blah, b.bleu, a.craw] <=> [b.blah, a.bleu, b.craw]}
Также можно использовать знак -
с sort_by
или sort_by!
, чтобы сделать обратный сортировку по цифрам (насколько я знаю, он работает только на числах, поэтому не пытайтесь использовать строки, так как это просто ошибки и убивает страницу).
Предположим, что a.craw
- целое число. Например:
something.sort_by!{|a| [a.blah, -a.craw, a.bleu]}
У меня была такая же основная проблема, и я решил это, добавив следующее:
class Inverter
attr_reader :o
def initialize(o)
@o = o
end
def <=>(other)
if @o.is && other.o.is
-(@o <=> other.o)
else
@o <=> other.o
end
end
end
Это оболочка, которая просто инвертирует функцию <= > , которая затем позволяет вам делать такие вещи:
your_objects.sort_by {|y| [y.prop1,Inverter.new(y.prop2)]}
Enumerable#multisort
- это общее решение, которое может быть применено к массивам любого размера, а не только для двух элементов. Аргументы - это логические значения, указывающие, следует ли сортировать определенное поле по возрастанию или убыванию (использование ниже):
items = [
[3, "Britney"],
[1, "Corin"],
[2, "Cody"],
[5, "Adam"],
[1, "Sally"],
[2, "Zack"],
[5, "Betty"]
]
module Enumerable
def multisort(*args)
sort do |a, b|
i, res = -1, 0
res = a[i] <=> b[i] until !res.zero? or (i+=1) == a.size
args[i] == false ? -res : res
end
end
end
items.multisort(true, false)
# => [[1, "Sally"], [1, "Corin"], [2, "Zack"], [2, "Cody"], [3, "Britney"], [5, "Betty"], [5, "Adam"]]
items.multisort(false, true)
# => [[5, "Adam"], [5, "Betty"], [3, "Britney"], [2, "Cody"], [2, "Zack"], [1, "Corin"], [1, "Sally"]]
Я уже давно использую рецепт Гленна. Я устал от копирования кода из проекта в проект снова и снова, я решил сделать его жемчужиной: