Как я могу выполнить сортировку по нескольким условиям с разными заказами?
Вопрос
Я бы действительно хотел справиться с этим без обезьяньего исправления, но я пока не смог найти другого варианта.
У меня есть массив (на 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 | block.Вы не можете использовать {|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
это универсальное решение, которое может быть применено к массивам любой размер, а не только те, у которых есть 2 элемента.Аргументы - это логические значения, которые указывают, следует ли сортировать конкретное поле по возрастанию или по убыванию (использование приведено ниже).:
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"]]
Я уже довольно давно пользуюсь рецептом Гленна.Устав снова и снова копировать код из проекта в проект, я решил сделать его жемчужиной: