Как я могу сортировать по нескольким условиям с разными заказами? - PullRequest
18 голосов
/ 16 сентября 2008

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

У меня есть массив (в Ruby), который мне нужно отсортировать по нескольким условиям. Я знаю, как использовать метод сортировки, и я использовал хитрость при сортировке с использованием массива опций для сортировки по нескольким условиям. Однако в этом случае мне нужно первое условие для сортировки по возрастанию и второе для сортировки по убыванию. Например:

ordered_list = [[1, 2], [1, 1], [2, 1]]

Есть предложения?

Edit: только что понял, я должен упомянуть, что я не могу легко сравнить первое и второе значения (на самом деле я работаю с атрибутами объекта здесь). Так что для простого примера это больше похоже на:

ordered_list = [[1, "b"], [1, "a"], [2, "a"]]

Ответы [ 5 ]

33 голосов
/ 16 сентября 2008

Как насчет:


ordered_list = [[1, "b"], [1, "a"], [2, "a"]]
ordered_list.sort! do |a,b|
  [a[0],b[1]] <=> [b[0], a[1]]
end

8 голосов
/ 04 июля 2012

Мне приснился кошмар времени, когда я пытался выяснить, как отменить сортировку определенного атрибута, но обычно сортирует два других. Просто заметка о сортировке для тех, кто приходит после этого и смущен | a, b | блочный синтаксис. Вы не можете использовать стиль блока {|a,b| a.blah <=> b.blah} с sort_by! или sort_by. Он должен использоваться с sort! или sort. Также, как указывалось ранее другими авторами, поменяйте местами a и b через оператор сравнения <=>, чтобы изменить порядок сортировки. Как это:

Для сортировки по бла и кроу, но для сортировки по блю в обратном порядке выполните следующее:

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]}
4 голосов
/ 16 сентября 2008

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"]]
4 голосов
/ 16 сентября 2008

У меня была такая же основная проблема, и я решил ее, добавив:

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)]}
2 голосов
/ 18 июля 2010

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

http://github.com/dadooda/invert

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...