Contador automático em Ruby para cada um?

134

Eu quero usar um para cada e um contador:

i=0
for blah in blahs
    puts i.to_s + " " + blah
    i+=1
end

Há uma melhor forma de fazê-lo?

Nota: Não sei se blahsé uma matriz ou um hash, mas fazer blahs[i]isso não tornaria muito mais sexy. Também gostaria de saber como escrever i++em Ruby.


Tecnicamente, a resposta de Matt e Squeegy veio em primeiro lugar, mas eu estou dando a melhor resposta para paradoja, então espalhe um pouco os pontos no SO. Também sua resposta teve a nota sobre as versões, que ainda são relevantes (desde que o meu Ubuntu 8.04 esteja usando o Ruby 1.8.6).


Deveria ter usado o puts "#{i} #{blah}"que é muito mais sucinto.

Dan Rosenstark
fonte
Não há operador de incremento no Ruby. O n + = 1 que você escreveu lá é o equivalente mais próximo. Teria que ser açúcar sintático para n + = 1, que é em si mesmo uma abreviação de n = n + 1. A ideia do ++ foi rejeitada porque oculta o fato de você estar reatribuindo a variável. Rubyurl.com/Dsb1
Chuck
Agradável! Obrigado Chuck. Fui forçado a aprender ++ i e i ++ em Java, então pensei que sempre estaria lá.
11119 Dan Rosenstark

Respostas:

190

Como as pessoas disseram, você pode usar

each_with_index

mas se você quiser índices com um iterador diferente de "each" (por exemplo, se desejar mapear com um índice ou algo parecido), concatenar enumeradores com o método each_with_index ou simplesmente usar with_index:

blahs.each_with_index.map { |blah, index| something(blah, index)}

blahs.map.with_index { |blah, index| something(blah, index) }

Isso é algo que você pode fazer a partir do ruby ​​1.8.7 e 1.9.

paradoja
fonte
1
Vale a pena notar que isso é novo no 1.9.
Zach Langley
1
Bem manchado. Na verdade, também está no 1.8.7, mas vale a pena acrescentar.
paradoja
por que estou no Ruby 1.8.6 se eu acabei de instalar a coisa toda no Ubuntu? O 1.8.7 é experimental / beta?
11119 Dan Rosenstark
Qual Ubuntu você está usando? Em Intrepid, há 1.8.7. É a última versão estável ( ruby-lang.org/en/downloads ). No entanto, o monkeypatch ruby ​​1.8.6 pode ter o mesmo comportamento (consulte strictlyuntyped.com/2008/09/ruby-187s-enumerator-class.html ).
paradoja
3
Eu me cansei da distribuição estar atrasada e comecei a usar o rvm para gerenciar minha instalação do Ruby no Ubuntu e Linux Mint.
o homem de lata
55
[:a, :b, :c].each_with_index do |item, i|
  puts "index: #{i}, item: #{item}"
end

Você não pode fazer isso com for. Eu geralmente gosto da ligação mais declarativa para cada um pessoalmente. Em parte porque é fácil fazer a transição para outras formas quando você atinge o limite da sintaxe for.

Alex Wayne
fonte
Bom, vejo o ponto sobre os limites com a sintaxe for. Eu tenho que me acostumar com blocos com vários parâmetros.
10119 Dan Rosenstark
11

Sim, é collection.eachfazer loops e each_with_indexobter o índice.

Você provavelmente deveria ler um livro sobre Ruby, porque isso é fundamental para Ruby e, se você não o conhecer, estará com um grande problema (tente: http://poignantguide.net/ruby/ ).

Retirado do código fonte do Ruby:

 hash = Hash.new
 %w(cat dog wombat).each_with_index {|item, index|
   hash[item] = index
 }
 hash   #=> {"cat"=>0, "wombat"=>2, "dog"=>1}
Matt Rogish
fonte
Não tem problema, feliz em ajudar. Não pretendia ser "mesquinho" sobre o bloco .each - essas são construções fundamentais de rubi e aprendê-las em tempo real será muito, muito doloroso. :) Melhor morder a bala e passar algumas horas lendo!
22811 Matt Rogish
6

Se você não possui a nova versão each_with_index, pode usar o zipmétodo para emparelhar índices com elementos:

blahs = %w{one two three four five}
puts (1..blahs.length).zip(blahs).map{|pair|'%s %s' % pair}

que produz:

1 one
2 two
3 three
4 four
5 five
George
fonte
1
Onde posso encontrar esse código na sua resposta '%s %s' % [1, "two"]nos documentos do Ruby? Obrigado por sua ajuda e por conservar espaço vertical usando uma linha para compactar e mapear.
Dan Rosenstark
1
Nesse contexto, o operador% -sign é um método da classe String. Você pode ler sobre isso em ruby-doc.org/core/classes/String.html#M000770 . Ou você pode digitar ri String #% em um prompt de comando. Ou você pode digitar ri% para ver todas as classes documentadas que o reconhecem, por exemplo, o significado mais familiar em ri Fixnum #%.
1959 George
4

Quanto à sua pergunta sobre fazer i++, bem, você não pode fazer isso em Ruby. A i += 1afirmação que você teve é ​​exatamente como deveria fazê-lo.

papa
fonte
1

Se blahsfor uma classe que mescla em Enumerable, você poderá fazer isso:

blahs.each_with_index do |blah, i|
  puts("#{i} #{blah}")
end
Roy Pardee
fonte
1

Se você deseja obter o índice de ruby ​​para cada um, pode usar

.each_with_index

Aqui está um exemplo para mostrar como .each_with_indexfunciona:

range = ('a'..'z').to_a
length = range.length - 1
range.each_with_index do |letter, index|
    print letter + " "
    if index == length
        puts "You are at last item"
    end
end

Isso imprimirá:

a b c d e f g h i j k l m n o p q r s t u v w x y z You are at last item
Ilyas karim
fonte