Сортировка: сортировка массива на основе нескольких условий в Ruby - PullRequest
21 голосов
/ 17 января 2012

У меня есть многомерный массив, например:

[
  [name, age, date, gender]
  [name, age, date, gender]
  [..]
]

Мне интересно, как лучше отсортировать этот массив по нескольким условиям ... Например, как бы я отсортировал по age сначала , затем по имени?

Я возился с методом sort вот так:

array.sort { |a,b| [ a[1], a[0] ] <=> [ b[1], b[0] ] }

Кроме того, что я не совсем понимаю этот синтаксис, я не получаю ожидаемых результатов. Должен ли я использовать метод sort? Должен ли я индивидуально сравнивать результаты по mapping массиву?

Ответы [ 3 ]

43 голосов
/ 17 января 2012

Вы должны всегда использовать sort_by для сортировки по ключу. Мало того, что это намного более читабельно, это также намного более эффективно. Кроме того, я бы также предпочел использовать деструктурирующую привязку, опять же, для удобства чтения:

ary.sort_by {|name, age| [age, name] }
14 голосов
/ 17 января 2012

Это должно сработать:

array.sort { |a,b| [ a[1], a[0] ] <=> [ b[1], b[0] ] }

Так что же это делает?Он использует много идиом Ruby.

  • Первый - это блоки, которые похожи на обратные вызовы или анонимные функции / классы в других языках.Метод Array sort использует их для сравнения двух элементов на основе возвращаемого значения блока.Вы можете прочитать все о них здесь .
  • Далее следует оператор <=>.Возвращает -1, если первый аргумент меньше второго, 0, если они равны, и 1, если первый больше второго.Когда вы используете его с массивами, он будет сравнивать элементы поэлементно, пока один из них не вернет -1 или 1. Если массивы равны, вы получите 0.
7 голосов
/ 17 января 2012

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


Это работает для меня

people = [
      ["bob", 15, "male"], 
      ["alice", 25, "female"], 
      ["bob", 56, "male"], 
      ["dave", 45, "male"], 
      ["alice", 56, "female"], 
      ["adam", 15, "male"]
    ]

people.sort{|a,b| (a[1] <=> b[1]) == 0 ? (a[0] <=> b[0]) : (a[1] <=> b[1]) }

# The sorted array is

[["adam", 15, "male"], 
 ["bob", 15, "male"], 
 ["alice", 25, "female"], 
 ["dave", 45, "male"], 
 ["alice", 56, "female"], 
 ["bob", 56, "male"]]

То, что это делает, сравнивает сначала по возрасту, а если возраст совпадает (<=> возвращается 0), то сравнивает имя.

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