Как Array#sort работает, когда блок передается?

У меня есть проблема при понимании как array.sort{ |x,y| block } работы точно, следовательно как использовать его?

Пример из документации Ruby:

   a = [ "d", "a", "e", "c", "b" ]
   a.sort                     #=> ["a", "b", "c", "d", "e"]
   a.sort { |x,y| y <=> x }   #=> ["e", "d", "c", "b", "a"]

74
задан Mohsen Nosratinia 8 May 2015 в 14:20
поделиться

5 ответов

В вашем примере

a.sort

эквивалентно

a.sort { |x, y| x <=> y }

Как вы знаете, чтобы отсортировать массив, вам нужно иметь возможность сравнивать его элементы (если вы сомневаетесь в этом, просто попробуйте реализовать любой алгоритм сортировки без использования какого-либо сравнения, нет <, > , <= или > = ).

Предоставленный вами блок на самом деле является функцией, которая будет вызываться алгоритмом sort для сравнения двух элементов. То есть x и y всегда будут некоторыми элементами входного массива, выбранными алгоритмом sort во время его выполнения.

Алгоритм sort предполагает, что эта функция / блок сравнения будет соответствовать требованиям для метода <=> :

  • вернуть -1, если x
  • return 0, если x = y
  • , возврат 1, если x> y

Невозможность предоставить адекватную функцию / блок сравнения приведет к массиву, порядок которого не определен.

Теперь вы должны понять, почему

a.sort { |x, y| x <=> y }

и

a.sort { |x, y| y <=> x }

возвращают один и тот же массив в противоположном порядке.


Чтобы уточнить, что добавил Тейт Джонсон, если вы реализуете функцию сравнения <=> в любом из ваших классов, вы получите следующее

  1. Вы можете включить модуль Comparable ] в вашем классе, который автоматически определит для вас следующие методы: между? , == , > = , <, <= и > .
  2. Экземпляры вашего класса теперь могут быть отсортированы с использованием вызова по умолчанию (т. Е. Без аргументов) для sort .

Обратите внимание, что метод <=> уже предоставляется везде, где это имеет смысл, в стандартной библиотеке ruby ​​( Bignum , Array , File :: Stat , Fixnum , String , Time и т. Д.).

121
ответ дан 24 November 2019 в 11:55
поделиться

Некоторые прочие моменты:

  • x и y называются параметрами блока. Метод сортировки в основном гласит: «Я дам вам x и y, вы определяете, x или y должно быть первым, а я позабочусь о скучных вещах, связанных с сортировкой»
  • <=> называется оператор космического корабля .
4
ответ дан 24 November 2019 в 11:55
поделиться

В:

a.sort {|x,y| y <=> x }   #=> ["e", "d", "c", "b", "a"]

что такое x и y?

x и y - это элементы, сравниваемые алгоритмом сортировки.

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

Для основных данных (чисел, строк, даты и т. Д.) Естественный порядок предопределен, но для элемента клиента (т.е. сотрудника) вы определяете, кто идет впереди кого в сравнении. Этот блок дает вам возможность определить это.

и что происходит в y <=> x?

Здесь они сравнивают элементы в порядке убывания (те, у которых «более высокое» значение, идут первыми), а не в естественном порядке ( x <=> y )

Метод <=> означает "compareTo" и возвращает 0, если элементы эквивалентны, или < 0, если x идет перед y или > 0, если x идет после y

3
ответ дан 24 November 2019 в 11:55
поделиться

<=> - это метод ruby, который возвращает ( self. <=> (Аргумент) )

  • -1, если self <аргумент
  • 0, если self == аргумент
  • 1, если self> аргумент

x и y являются элементами массива. Если блок не указан, функция sort использует x <=> y ​​, в противном случае результат блока говорит, должен ли x быть перед y.

array.sort{|x, y| some_very_complicated_method(x, y) }

Здесь, если some_very_complicated_method (x, y) возвращает что-то, что <0, x считается <чем y и так далее ...

7
ответ дан 24 November 2019 в 11:55
поделиться

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

Но когда вы сортируете другие объекты, может потребоваться обеспечить способ сравнения (каждого) из них. Допустим, у вас есть массив объектов класса Person. Возможно, вы не можете определить, что объект bob больше объекта mike (т.е. у класса Person не реализован метод <=>). В этом случае вам нужно будет предоставить код, объясняющий, в каком порядке вы хотите отсортировать эти объекты для метода sort. Вот тут-то и вступает в действие блочная форма.

people.sort{|p1,p2| p1.age <=> p2.age}
people.sort{|p1,p2| p1.children.count <=> p2.children.count}

и т.д. Во всех этих случаях метод sort сортирует их одинаково - используется один и тот же алгоритм. Отличие заключается в логике сравнения.

21
ответ дан 24 November 2019 в 11:55
поделиться