2013-05-10 11 views
5

Próbuję poniższy kod:"Każda" metoda Ruby nie iterująca nad wszystkimi elementami w tablicy?

a = [1,2,3,4] 
a.each do 
    puts "Removing #{a.last}" 
    a.pop 
end 

ale zamiast się wszystkie cztery numery pojawiło się tylko zdobyć pierwszy 3. Rzeczywiście, robi coś podobnego stawia a.length zwraca 1 i wkłada-ing to pokazuje element "1" nadal tam jest.

Jak należy prawidłowo korzystać z metody? (Używam Ruby 2.0).

+1

Co właściwie próbujesz osiągnąć? – Stefan

+0

To, co próbowałem osiągnąć, to drukowanie każdego elementu tablicy po jej wyskoczeniu. Próbuję nauczyć się Rubiego przez e-książki i takie. Wygląda na to, że mam przed sobą dość drogi. –

Odpowiedz

5

Podejrzewam, że tak się dzieje, ponieważ trwa iteracja nad elementami listy podczas modyfikowania listy.

Spróbuj wykonać następujące czynności:

a = [1,2,3,4] 
until a.empty? do 
    puts "Removing #{a.last}" 
    a.pop 
end 
+0

Dzięki za odpowiedź. Dokładnie na miejscu. –

1

Spójrz na wyjściu, co sprawia, że ​​jasne, dlaczego wydaje się wam nie każdy zaczyna działać ze wszystkich elementów tablicy. Ponieważ jesteś pop (ing) Array#pop, więc elementy z ostatniego są usuwane. Kiedy każdy przechodzi 2 do bloku, a następnie oryginalna tablica a mam pusty, więc each zatrzymuje iteracji .:

a = [1,2,3,4] 
a.each do |i| 
    puts i 
    puts "Removing #{a.last}" 
    p a.pop 
    p "========" 
end 

wyjściowa:

1 
Removing 4 
4 
"========" 
2 
Removing 3 
3 
"========" 

Więc można użyć poniżej:

a = [1,2,3,4] 
(0...a.size).each do |i| 
p a.pop 
end 

wyjściowa:

4 
3 
2 
1 
+0

Dziękuję za pouczającą odpowiedź. –

0
a = [1,2,3,4] 
a.length.times do 
    puts "Removing #{a.last}" 
    a.pop 
end 
+0

Dziękuję za odpowiedź. –

2

Niektóre inne odpowiedzi powiedzieć dlaczego Twój kod nie działa.

Alternatywnym sposobem na to byłoby tak (pod warunkiem, że nie masz nil lub false w a):

a = [1,2,3,4] 
while e = a.pop 
    puts "Removing #{e}" 
end 
+0

Dziękuję za kolejne zgłoszenie. –

0

Spróbuj tego:

a.count.times do a.pop and puts "Removing #{a.last + 1 rescue 1}" end 

powinien zrobić to samo w pętla do wykonania:

3

Problem
Podczas iteracji ponad a zmieniasz to.

Wyjaśnienie problemu
Oznacza to, że po usunięciu elementu każda metoda zostanie wyrzucony, bo nagle liczba elementów a zawiera jeden mniej. A zatem indeksowanie jest również odrzucane.
Gdybym tylko wykonać to:

a = [1,2,3,4] 
a.each do 
    |thing| 
    puts thing 
    a.delete(thing) 
end 

dostanę wyjście [1,3]. Dzieje się tak, ponieważ:
Przed usunięciem 1 z listy, która jest na indeksie 0, 2 jest na indeksie 1. Po usunięciu 1, 2 ma indeks 0 zamiast 1, więc nie 2 to kolejny element, który jest powtarzany, ale 3!

Przy okazji można zdefiniować lokalną zmienną blokową, tak jak zrobiłem to z thing, aby uzyskać dostęp do każdego elementu, który jest iterowany.

Rozwiązanie
W celu uzyskania tego, co chcesz, musisz utworzyć kopię i pracować nad tym.

a = [1,2,3,4] 
b = a.clone 
a.each do 
    |thing| 
    puts thing 
    b.delete(thing) 
end 

Teraz pozostaje taki sam podczas iteracji i zamiast tego zmienia się b. Więc na końcu tej pętli a = [1,2,3,4] i b =[].
Po wymowie a = b otrzymasz oczekiwany rezultat.

Oczywiście można to zaadaptować do otwierania elementów od tyłu. Po prostu upewnij się, że działasz na kopii, więc nie zmieniasz elementu podczas iteracji nad nim.

+0

Dziękuję za bardzo pouczającą odpowiedź. Pomocna i wyciągnięta lekcja. –

Powiązane problemy