Правильный способ заполнения массива с помощью Range в Ruby


202

Я работаю над книгой, в которой приводятся примеры преобразования диапазонов в эквивалентные массивы с использованием их методов "to_a"

Когда я запускаю код в IRB, я получаю следующее предупреждение

 warning: default `to_a' will be obsolete

Какова правильная альтернатива использованию to_a?

Существуют ли альтернативные способы заполнения массива Range?


7
Большое предостережение о преобразовании диапазона в массив - большой диапазон может потреблять много памяти при построении массива, поэтому используйте его с осторожностью. Вместо создания массива может быть лучше выполнить итерации по диапазону, как если бы вы использовали массив, чтобы снизить потребление памяти. Это одна из тех вещей, которые «применяются по мере необходимости».
Жестянщик

Ответы:


358

Вы можете создать массив с диапазоном, используя сплат,

>> a=*(1..10)
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

используя Kernel Arrayметод,

Array (1..10)
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

или используя to_a

(1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

1
Что делать, если массив уже создан, и вы хотите добавить диапазон к нему: у меня есть order = 1. Потом order << (2.25).to_a. Но это создает другой массив внутри массива, я просто хочу диапазон от 2 до 25. Тем не менее, если я пытаюсь order << (2.25)получить ошибку, я не могу преобразовать Range в Integer.
Какубей

1
@kakubei использовать concatвместо <<. Кроме того, вы не должны получать сообщение «не можете преобразовать Range в Integer», если orderэто не целое число - в этом случае вы будете сдвигать биты, а не добавлять массив.
Кельвин

3
опция Splat не работает для Ruby 1.8.7, я бы порекомендовал использовать (1..10).to_aдля обратной совместимости
kylewelsby

5
Вы используете сплат противно. Лучший вариант выглядит [*1..10].
Хаулет

2
какой самый быстрый способ ??
Андрей Ясинишин

79

Это работает для меня в IRB:

irb> (1..4).to_a
=> [1, 2, 3, 4]

Я замечаю, что:

irb> 1..4.to_a
(irb):1: warning: default `to_a' will be obsolete
ArgumentError: bad value for range
        from (irb):1

Так что, возможно, вам не хватает скобок?

(Я использую Ruby 1.8.6 уровня исправления 114)


7
Объяснение : без скобок вы вызываете метод to_a из экземпляра класса Fixnum (в данном случае 4), а не из диапазона 1..4. Если вы запустите Fixnum.methods.include?(to_a)ruby 1.9.2, вы заметите, что метод to_a больше не определен, поэтому вы получили это сообщение об амортизации в 08
Pierre

@Pierre Я думаю, что вы имели в видуFixnum.instance_methods.include?(:to_a)
Кельвин

@Kelvin - На самом деле, methods.include?более информативно: $ irb irb(main):001:0> Fixnum.methods.include?(to_a) (irb):1: warning: default to_a 'будет устаревшим=> false irb(main):002:0> Fixnum.instance_methods.include?(:to_a) => false
Ричард Тернер

1
@RichardTurner Полагаю, вы используете ruby ​​1.8. Боюсь, вы неправильно понимаете, что вызывает to_aпредупреждение в первой форме. Это потому , что вы звоните to_aна self- вы на самом деле не проверки , является ли to_aэто метод Fixnum. Попробуйте позвонить to_aсамостоятельно, и вы увидите то же самое предупреждение.
Кельвин

@ Кельвин - Дух! Пенни падает. Спасибо.
Ричард Тернер

34

Похоже, вы делаете это:

0..10.to_a

Предупреждение от Fixnum # to_a, а не от Range # to_a. Попробуйте это вместо этого:

(0..10).to_a



4

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

irb(main):007:0> Array(1..5)
=> [1, 2, 3, 4, 5]
irb(main):008:0> Array(5..1)
=> []

Это из-за реализации диапазонов.
Поэтому мне пришлось использовать следующую опцию:

(1..5).to_a.reverse

4
Сегодня я обнаружил, 5.downto(1).to_aчто это еще один способ выражения уменьшающегося диапазона stackoverflow.com/a/8927009/703903
odlp
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.