Maneira correta de preencher uma matriz com um intervalo em Ruby

201

Estou trabalhando em um livro que fornece exemplos de intervalos sendo convertidos em matrizes equivalentes usando seus métodos "to_a"

Quando executo o código no irb, recebo o seguinte aviso

 warning: default `to_a' will be obsolete

Qual é a alternativa correta para usar to_a?

existem maneiras alternativas de preencher uma matriz com um intervalo?

Willbill
fonte
7
A grande ressalva de converter um intervalo em um array é que ele pode consumir muita memória quando o array é construído, portanto, use-o com cuidado. Em vez de criar a matriz, seria melhor iterar no intervalo, como faria com uma matriz para manter o consumo de memória baixo. É uma daquelas coisas que "aplicam conforme necessário".
the Tin Man

Respostas:

357

Você pode criar uma matriz com um intervalo usando splat,

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

usando o Kernel Arraymétodo

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

ou usando to_a

(1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Zamith
fonte
1
E se a matriz já estiver criada e você desejar adicionar um intervalo a ela: eu tenho order = 1. Então order << (2.25).to_a. Mas isso cria outra matriz dentro da matriz, eu simplesmente quero o intervalo de 2 a 25. No entanto, se eu tentar, order << (2.25)eu recebo o erro não pode converter Range em Inteiro.
kakubei
1
@kakubei use em concatvez de <<. Além disso, você não deve obter "não é possível converter o intervalo em número inteiro", a menos que orderseja um número inteiro - nesse caso, você trocaria os bits, não acrescentaria o array.
Kelvin
3
a opção Splat não trabalho para o Ruby 1.8.7, eu recomendo usar (1..10).to_apara compatibilidade com versões anteriores
kylewelsby
5
Seu uso do splat é desagradável. Melhor opção é [*1..10].
Hauleth
2
qual é a maneira mais rápida ??
Andrey Yasinishyn
79

Isso funciona para mim no irb:

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

Eu reparei nisso:

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

Então, talvez você esteja perdendo os parênteses?

(Estou executando o Ruby 1.8.6 patchlevel 114)

Daniel Lucraft
fonte
7
Explicação : sem os parênteses, você está chamando o método to_a a partir de uma instância da Classe Fixnum (neste caso, 4), não no intervalo 1..4. Se você executar o Fixnum.methods.include?(to_a)ruby 1.9.2, notará que o método to_a não está mais definido, portanto, por que você estava recebendo essa mensagem de depreciação em 08
Pierre
@Pierre Eu acho que você quis dizerFixnum.instance_methods.include?(:to_a)
Kelvin
@Kelvin - Na verdade, methods.include?é mais informativa: $ irb irb(main):001:0> Fixnum.methods.include?(to_a) (irb):1: warning: default to_a' será obsoleto=> false irb(main):002:0> Fixnum.instance_methods.include?(:to_a) => false
Richard Turner
1
@RichardTurner Suponho que você esteja usando o ruby ​​1.8. Receio que você esteja entendendo mal o que está acionando o to_aaviso na primeira forma. É porque você está chamando to_ade self- você não está realmente verificando se to_aé um método de Fixnum. Tente ligar to_asozinho e você verá o mesmo aviso.
Kelvin
@Kelvin - Duh! O centavo cai. Obrigado.
Richard Turner
34

Parece que você está fazendo isso:

0..10.to_a

O aviso é do Fixnum # to_a, não do intervalo # to_a. Tente isso:

(0..10).to_a
Richard Turner
fonte
9

Verifique isto:

a = [*(1..10), :top, *10.downto( 1 )]
Boris Stitnicky
fonte
2
O * 10.downto (1) era o que eu procurava, obrigado!
Daniel
6

Esta é outra maneira:

irb> [*1..10]

=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Jesús Andrés Valencia Montoya
fonte
4

Eu apenas tentei usar faixas de maior a menor quantidade e obtive o resultado que eu não esperava:

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

Isso é devido às implementações de intervalos.
Então eu tive que usar a seguinte opção:

(1..5).to_a.reverse
Nickolay Kondratenko
fonte
4
Hoje eu descobri 5.downto(1).to_aque é outra maneira de expressar uma diminuição da gama stackoverflow.com/a/8927009/703903
odlp