У меня есть проблема при понимании как 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"]
В вашем примере
a.sort
эквивалентно
a.sort { |x, y| x <=> y }
Как вы знаете, чтобы отсортировать массив, вам нужно иметь возможность сравнивать его элементы (если вы сомневаетесь в этом, просто попробуйте реализовать любой алгоритм сортировки без использования какого-либо сравнения, нет <
, >
, <=
или > =
).
Предоставленный вами блок на самом деле является функцией, которая будет вызываться алгоритмом sort
для сравнения двух элементов. То есть x
и y
всегда будут некоторыми элементами входного массива, выбранными алгоритмом sort
во время его выполнения.
Алгоритм sort
предполагает, что эта функция / блок сравнения будет соответствовать требованиям для метода <=>
:
Невозможность предоставить адекватную функцию / блок сравнения приведет к массиву, порядок которого не определен.
Теперь вы должны понять, почему
a.sort { |x, y| x <=> y }
и
a.sort { |x, y| y <=> x }
возвращают один и тот же массив в противоположном порядке.
Чтобы уточнить, что добавил Тейт Джонсон, если вы реализуете функцию сравнения <=>
в любом из ваших классов, вы получите следующее
Comparable
] в вашем классе, который автоматически определит для вас следующие методы: между?
, ==
, > =
, <
, <=
и >
. sort
. Обратите внимание, что метод <=>
уже предоставляется везде, где это имеет смысл, в стандартной библиотеке ruby ( Bignum
, Array
, File :: Stat
, Fixnum
, String
, Time
и т. Д.).
Некоторые прочие моменты:
x
и y
называются параметрами блока. Метод сортировки в основном гласит: «Я дам вам x и y, вы определяете, x или y должно быть первым, а я позабочусь о скучных вещах, связанных с сортировкой» <=>
называется оператор космического корабля . В:
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
<=>
- это метод ruby, который возвращает ( 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 и так далее ...
Когда у вас есть массив, скажем, целых чисел для сортировки, то для метода 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
сортирует их одинаково - используется один и тот же алгоритм. Отличие заключается в логике сравнения.