Как я могу выполнить сортировку по нескольким условиям с разными заказами?

StackOverflow https://stackoverflow.com/questions/73032

  •  09-06-2019
  •  | 
  •  

Вопрос

Я бы действительно хотел справиться с этим без обезьяньего исправления, но я пока не смог найти другого варианта.

У меня есть массив (на 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"]]

Я уже довольно давно пользуюсь рецептом Гленна.Устав снова и снова копировать код из проекта в проект, я решил сделать его жемчужиной:

http://github.com/dadooda/invert

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top