Сортировать по трем элементам в подрешетках - PullRequest
0 голосов
/ 30 октября 2018

Учитывая следующую коллекцию:

 collection = [
  ["Pennsylvania", "Bucks", "Doctor"], 
  ["New Jersey", "Essex", "Lawyer"], 
  ["New Jersey", "Essex", "Firefighter"],
  ["Florida", "Palm Beach", "Doctor"], 
  ["Florida", "Broward", "Doctor"],
  ["Florida", "Palm Beach", "Scientist"] 
]

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

[
  ["Florida", "Broward", "Doctor"],
  ["Florida", "Palm Beach", "Doctor"], 
  ["Florida", "Palm Beach", "Scientist"],
  ["Pennsylvania", "Bucks", "Doctor"], 
  ["New Jersey", "Essex", "Firefighter"],
  ["New Jersey", "Essex", "Lawyer"], 
]

Я не могу понять это с помощью итератора sort_by. Я попробовал это:

collection.sort_by {|a,b| a <=> b }
 => [["Florida", "Palm Beach", "Doctor"], ["Florida", "Palm Beach", "Doctor"], ["New Jersey", "Essex", "Firefighter"], ["New Jersey", "Essex", "Lawyer"], ["Florida", "Broward", "Scientist"], ["Pennsylvania", "Bucks", "Doctor"]] 

Очевидно, не те результаты, которые я ожидал. Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Здесь есть два инструмента, каждый из которых может получить одинаковый результат, но которые имеют разные последствия с точки зрения производительности. sort_by должен преобразовать каждый элемент один раз и только один раз для сравнения и сортировки. sort должен запустить этот блок для каждого сравнения , где обычно будет N x log (N) сравнений, выполняемых для каждой операции сортировки. Для больших списков может быть значительно больше операций, чем количество записей в массиве.

Если вы выполняете дорогостоящее преобразование, sort_by является победителем здесь. Для действительно простых операций sort иногда лучше, но это субъективный вызов.

Например, два подхода к одному и тому же результату:

array = [ 7, 2, 5, 3, 4, 1, 6 ]

array.sort_by { |a| -a }
# => [7, 6, 5, 4, 3, 2, 1]

# Sort by negated values
array.sort { |a,b| -a <=> -b }
# => [7, 6, 5, 4, 3, 2, 1]

# Reverse the comparison, reverse the sort order
array.sort { |a,b| b <=> a }

Все это допустимые подходы, но преимущество подхода sort_by становится более очевидным, когда вы минимизируете свой код следующим образом:

# Sort by unary minus (Integer#-@)
array.sort_by(&:-@)

Где в вашем конкретном случае, скажем, вы хотели отсортировать без учета регистра:

collection = [
  ["NEW JERSEY", "Essex", "Lawyer"], 
  ["Florida", "Palm Beach", "Doctor"], 
  ["New Jersey", "ESSEX", "Firefighter"],
  ["Pennsylvania", "Bucks", "Doctor"], 
  ["florida", "Broward", "Doctor"],
  ["Florida", "Palm Beach", "Scientist"] 
]

s = collection.sort_by do |e|
  e.map(&:downcase)
end
# => [["florida", "Broward", "Doctor"], ["Florida", "Palm Beach", "Doctor"], ... ]

Вызов downcase для массива является довольно дорогой операцией, поэтому вы хотите выполнить это как можно меньше раз, чтобы избежать создания большого количества дублированных объектов, которые необходимо собирать мусором.

0 голосов
/ 30 октября 2018

Вы используете Enumerable#sort_by, когда хотите использовать Array#sort.

Enumerable#sort_by

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

Array#sort

Блок должен реализовать сравнение между a и b и возвращать целое число меньше 0, если b следует за a, 0, когда a и b эквивалентны, или целое число больше 0, когда следует за b.

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