O PHP, apesar de todas as suas verrugas, é muito bom nesse sentido. Não há diferença entre uma matriz e um hash (talvez eu seja ingênuo, mas isso parece obviamente correto para mim), e para iterar através de qualquer um
foreach (array/hash as $key => $value)
Em Ruby, existem várias maneiras de fazer esse tipo de coisa:
array.length.times do |i|
end
array.each
array.each_index
for i in array
Hashes fazem mais sentido, já que eu sempre uso
hash.each do |key, value|
Por que não posso fazer isso para matrizes? Se eu quiser me lembrar de apenas um método, acho que posso usar each_index
(já que ele disponibiliza o índice e o valor), mas é irritante ter que fazer em array[index]
vez de apenas value
.
Ah, claro, eu esqueci array.each_with_index
. No entanto, este é uma merda, porque vai |value, key|
e hash.each
vai |key, value|
! Isso não é insano?
array#each_with_index
usa|value, key|
porque o nome do método implica a ordem, enquanto a ordem usada parahash#each
imita ahash[key] = value
sintaxe?Respostas:
Isso irá percorrer todos os elementos:
Impressões:
Isso irá percorrer todos os elementos, fornecendo o valor e o índice:
Impressões:
Não tenho muita certeza da sua pergunta, qual você está procurando.
fonte
Eu acho que não há um caminho certo . Existem várias maneiras diferentes de iterar, e cada uma tem seu próprio nicho.
each
é suficiente para muitos usos, já que muitas vezes não me importo com os índices.each_ with _index
age como Hash # each - você obtém o valor e o índice.each_index
- apenas os índices. Eu não uso este frequentemente. Equivalente a "comprimento x vezes".map
é outra maneira de iterar, útil quando você deseja transformar uma matriz em outra.select
é o iterador a ser usado quando você deseja escolher um subconjunto.inject
é útil para gerar somas ou produtos ou coletar um único resultado.Pode parecer muito para lembrar, mas não se preocupe, você pode sobreviver sem conhecer todos eles. Mas quando você começar a aprender e usar os diferentes métodos, seu código se tornará mais limpo e claro, e você estará no seu caminho para o domínio do Ruby.
fonte
Não estou dizendo que
Array
->|value,index|
eHash
->|key,value|
não é insano (veja o comentário de Horace Loeb), mas estou dizendo que existe uma maneira sensata de esperar esse arranjo.Quando estou lidando com matrizes, estou focado nos elementos da matriz (não no índice porque o índice é transitório). O método é cada um com índice, ou seja, cada índice + ou | cada índice |, ou
|value,index|
. Isso também é consistente com o índice sendo exibido como um argumento opcional, por exemplo | valor | é equivalente a | value, index = nil | que é consistente com | valor, índice |.Quando estou lidando com hashes, geralmente estou mais focado nas chaves do que nos valores, e geralmente estou lidando com chaves e valores nessa ordem, seja
key => value
ouhash[key] = value
.Se você deseja digitar patos, use explicitamente um método definido como Brent Longborough mostrou ou um método implícito como maxhawkins mostrou.
Ruby é tudo sobre como acomodar o idioma para se adequar ao programador, não sobre o programador para se adequar ao idioma. É por isso que existem tantas maneiras. Existem muitas maneiras de pensar em algo. No Ruby, você escolhe o mais próximo e o restante do código geralmente cai de maneira extremamente clara e concisa.
Quanto à pergunta original, "Qual é a maneira" correta "de iterar através de uma matriz em Ruby?", Bem, acho que a maneira principal (ou seja, sem açúcar sintático poderoso ou poder orientado a objetos) é:
Mas Ruby é tudo sobre açúcar sintático poderoso e poder orientado a objetos, mas de qualquer maneira aqui é o equivalente a hashes, e as chaves podem ser ordenadas ou não:
Então, minha resposta é: "A maneira" correta "de iterar através de uma matriz no Ruby depende de você (ou seja, do programador ou da equipe de programação) e do projeto". O melhor programador Ruby faz a melhor escolha (de qual poder sintático e / ou qual abordagem orientada a objetos). O melhor programador de Ruby continua procurando outras maneiras.
Agora, quero fazer outra pergunta: "Qual é a maneira" correta "de percorrer um Range in Ruby de trás para frente?"! (Esta questão é como cheguei a esta página.)
É bom fazer (para a frente):
mas eu não gosto de fazer (para trás):
Bem, eu realmente não me importo muito de fazer isso, mas quando estou ensinando ao contrário, quero mostrar aos meus alunos uma simetria agradável (ou seja, com diferença mínima, por exemplo, apenas adicionando um reverso ou um passo -1, mas sem modificando qualquer outra coisa). Você pode fazer (por simetria):
e
que eu não gosto muito, mas você não pode fazer
Você poderia finalmente fazer
mas eu quero ensinar Ruby puro em vez de abordagens orientadas a objeto (ainda). Gostaria de iterar para trás:
Eu acredito que isso é impossível sem definir um
pred
método, o que significa modificar a classe Range para usá-lo. Se você puder fazer isso, entre em contato, caso contrário, a confirmação da impossibilidade seria apreciada, embora isso fosse decepcionante. Talvez o Ruby 1.9 resolva isso.(Obrigado pelo seu tempo lendo isso.)
fonte
1.upto(10) do |i| puts i end
e10.downto(1) do puts i end
meio que dá a simetria que você queria. Espero que ajude. Não tenho certeza se funcionaria para seqüências de caracteres e tal.[*1..10].each{|i| puts "i=#{i}" }
.Use each_with_index quando precisar de ambos.
fonte
As outras respostas são ótimas, mas eu queria destacar outra coisa periférica: as matrizes são ordenadas, enquanto que os Hashes não estão no 1.8. (No Ruby 1.9, os Hashes são ordenados por ordem de inserção de chaves.) Portanto, não faria sentido antes do 1.9 iterar sobre um Hash da mesma maneira / sequência que Arrays, que sempre tiveram uma ordem definida. Eu não sei qual é a ordem padrão para matrizes associativas PHP (aparentemente meu google fu também não é forte o suficiente para descobrir isso), mas não sei como você pode considerar matrizes PHP regulares e matrizes associativas PHP para ser "o mesmo" neste contexto, uma vez que a ordem das matrizes associativas parece indefinida.
Como tal, o modo Ruby parece mais claro e intuitivo para mim. :)
fonte
Tentar fazer a mesma coisa de maneira consistente com arrays e hashes pode ser apenas um cheiro de código, mas, com o risco de eu ser rotulado como um meio-patador de macaco maciço, se você estiver procurando por um comportamento consistente, isso faria o truque? ?:
fonte
Aqui estão as quatro opções listadas na sua pergunta, organizadas por liberdade de controle. Você pode querer usar um diferente, dependendo do que você precisa.
Basta passar por valores:
Basta acessar os índices:
Percorra índices + variável de índice:
Contagem do loop de controle + variável de índice:
fonte
Eu estava tentando criar um menu (em Camping e Markaby ) usando um hash.
Cada item possui 2 elementos: um rótulo de menu e um URL ; portanto, um hash parecia certo, mas o URL '/' para 'Home' sempre aparecia por último (como seria de esperar para um hash); portanto, os itens de menu apareciam incorretos ordem.
O uso de uma matriz com
each_slice
faz o trabalho:Adicionar valores extras para cada item de menu (por exemplo, como um nome de ID CSS ) significa apenas aumentar o valor da fatia. Portanto, como um hash, mas com grupos que consistem em qualquer número de itens. Perfeito.
Portanto, isso é apenas para agradecer por sugerir inadvertidamente uma solução!
Óbvio, mas vale a pena afirmar: sugiro verificar se o comprimento da matriz é divisível pelo valor da fatia.
fonte
Se você usar o mixin enumerável (como o Rails), poderá fazer algo semelhante ao snippet php listado. Basta usar o método each_slice e achatar o hash.
É necessário menos patch para macacos.
No entanto, isso causa problemas quando você tem uma matriz recursiva ou um hash com valores de matriz. No ruby 1.9, esse problema é resolvido com um parâmetro para o método flatten que especifica a profundidade da recuperação.
Quanto à questão de saber se é um cheiro de código, não tenho certeza. Geralmente, quando tenho que me inclinar para trás para repetir algo, dou um passo atrás e percebo que estou atacando o problema errado.
fonte
O caminho certo é aquele com o qual você se sente mais confortável e que faz o que deseja. Na programação, raramente existe uma maneira 'correta' de fazer as coisas, mais frequentemente há várias maneiras de escolher.
Se você se sentir confortável com certa maneira de fazer as coisas, faça exatamente isso, a menos que não funcione - então é hora de encontrar uma maneira melhor.
fonte
No Ruby 2.1, cada método com índice é removido. Em vez disso, você pode usar each_index
Exemplo:
produz:
fonte
each_with_index
não aparece na documentação é porque ela é fornecida peloEnumerable
módulo.Usar o mesmo método para iterar através de matrizes e hashes faz sentido, por exemplo, para processar estruturas de hash e matriz aninhadas, geralmente resultantes de analisadores, da leitura de arquivos JSON etc.
Uma maneira inteligente que ainda não foi mencionada é como ela é feita na biblioteca de extensões de biblioteca padrão do Ruby Facets . A partir daqui :
Já existe
Hash#each_pair
, um apelido deHash#each
. Portanto, após esse patch, também temosArray#each_pair
e podemos usá-lo de forma intercambiável para percorrer Hashes e Arrays. Isso corrige a insanidade observada do OP queArray#each_with_index
tem os argumentos do bloco revertidos em comparação comHash#each
. Exemplo de uso:fonte