2013-08-28 3 views
3

Как отсортировать массив диапазоновсортировать массив диапазонов

ranges = [Range.new(0, 3, true), Range.new(3, 5, true), Range.new(5, 7, true), Range.new(7, 9, true), Range.new(9, 11, true), Range.new(11, 100, true)] 
ranges.sort 
=> ArgumentError: comparison of Range with Range failed 
from (irb):7:in `sort' 
from (irb):7 
from /Users/praveena/.rvm/rubies/ruby-2.0.0-p247/bin/irb:16:in `<main>' 

Но когда я пытаюсь

2.0.0p247 :022 > (3...4) <=> (4...8) 
=> nil 
2.0.0p247 :023 > (3...4) <=> (1...2) 
=> nil 

Я-то отсутствует?

ответ

2

Кажется, что диапазон имеют реализацию <=>, но не полный. Позволяет проверить:

> Range.new(3,4) <=> Range.new(3,4) 
=> 0 
# It seems that it correctly identify when the two are equals 

> Range.new(3,4) <=> Range.new(4,4) 
=> nil 
# But it seems that it fails to fail when both are different! 

Этот метод определен в Range, потому что на самом деле определяется on the Object class (!!!), таким образом, каждый объект имеет этот метод, определенный, не означает, что он работает. Фактически реализация для диапазона является стандартной по умолчанию. Давайте проверим это:

# lets define a dummy class 
class A 
end 
=> nil 

# and create an object 
a = A.new 
=> #<A:0x9b1d998> 

# can correctly identify when equal 
a <=> a 
=> 0 

# but invalid answer when not equal! 
a <=> 1 
=> nil 

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

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

+1

Я подозреваю, что равенство - это четко определенная математическая концепция для «диапазона», но нет такой четко определенной концепции «больше чем «или« меньше »- по крайней мере, недостаточно, чтобы превратить его в ядро ​​языка, вы всегда можете придумать что-то, что сработает для вас. –

+0

@NeilSlater согласен, нет четко определенного и здравого смысла, чтобы сказать из двух разных диапазонов, один из которых больше. – fotanus

2

nil не является полезной величиной из операции сравнения для сортировки.

Если вы пытаетесь <=> между двумя Comparable объектами, a <=> b они всегда будут возвращать -1, 0 или 1 для «менее чем б», «а равен Ь», и «больше, чем б» соответственно.

Поэтому, чтобы отсортировать Range объекты, вам нужно будет переопределить <=> и определить себя в каком порядке они должны сортировать. Обратите внимание, это должно быть что-то вы сделали для того, чтобы отсортировать их, Range объекты не имеют неотъемлемый или значимый порядок сортировки.

Например, я мог бы решить, что диапазоны сортируются в порядке начала Range, и падают обратно к концу Range, если они равны:

class Range 
    def <=>(other) 
    [min, max] <=> [other.min, other.max] 
    end 
end 

[(1..3),(1...3),(4..5),(2..3)].sort 
=> [1...3, 1..3, 2..3, 4..5] 
+0

'nil' - вполне допустимое возвращаемое значение для' <=> ', и оно используется точно так же, как предполагается в этом случае. Это означает, что «эти два объекта не могут быть разумно упорядочены». –

+0

@ Jörg W Mittag: Да. Возможно, мне придется изменить свое первое предложение. Я не имею в виду «плохой, период». Я имею в виду «плохой для использования при сортировке». –

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