2015-02-17 4 views
4

Поэтому я хочу отсортировать мой массив координат в лексикографическом порядке. Но я не знаю, как это сделать. Каждый элемент в массиве представляет собой объект Coordinate, с Fixnum полями #x и #y.Сортировка в лексикографическом порядке

Я новичок в Ruby и не обязательно понимаю сортировку сортировки. Было бы что-то вроде этого?

coordinate_array.sort! { |a,b| a.x <==> b.x && a.y <==> b.y } 
+0

Вы можете улучшить свой вопрос, добавив короткий ввод и результат вычисления. – radubogdan

ответ

3

Первый оператор космический корабль <=> не <==>

Во-вторых, вы не совмещая эти 2 сравнения правильно: результат сравнения будет -1,0 или 1. Это все truthy значения и true && foo просто foo, так что ваш код будет просто сортировать по у значения

Вы могли бы написать это как

x_ordering = a.x <=> b.x 
x_ordering == 0 ? a.y <=> b.y : x_ordering 

Однако массив уже реализует <=>, так что вы можете просто сделать

array.sort! { |a,b| [a.x, a.y] <=> [b.x, b.y]} 

который немного terser и понятнее за счет создания 2 массивов в каждом сравнении

Можно даже сделать

array.sort_by! { |a| [a.x, a.y] } 

Это даже яснее, но с немного другим профилем памяти. Это создает массив с исходными значениями, замененными значениями, возвращаемыми блоком, и использует их для сортировки исходного массива.

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

+0

oh wow, мне было интересно, почему <==> давал синтаксические ошибки -_-. спасибо за демонстрацию –

3

Frederick Cheung's answer уже описывает, как сортировать по пользовательским атрибутам.

Другой вариант заключается в обеспечении порядка сортировки по умолчанию в счет внедрения Coordinate#<=>:

class Coordinate 
    # ... 

    def to_a 
    [x, y] 
    end 

    def <=>(other) 
    to_a <=> other.to_a 
    end 
end 

И просто позвоните:

coordinate_array.sort! 

Вы также можете включить Comparable подмешать который ...

(...) использует <=> для реализации обычного стандарта (<, <=, ==, >= и >) и метод between?.

+0

Upvote для ссылки на 'Comparable' (даже если вы не упомянули' между? '). –

0

Stefan уже описал, как реализовать метод <=>() для вашего класса. Вот еще один способ:

class Coordinate 
    attr_reader :x, :y 

    def to_s 
    "(#{x}, #{y})" 
    end 

    def initialize(x, y) 
    @x = x 
    @y = y 
    end 

    def <=>(other) 
    [x, y] <=> [other.x, other.y] 
    end 
end 


arr = [ 
    Coordinate.new(1, 2), 
    Coordinate.new(0, 3), 
    Coordinate.new(0, 2), 
] 

puts arr 
puts "-" * 10 
puts arr.sort! 

--output:-- 
(1, 2) 
(0, 3) 
(0, 2) 
---------- 
(0, 2) 
(0, 3) 
(1, 2) 

Смотрите Array docs для того, как [1, 1] <=> [1, 0] работ.

Смежные вопросы