2009-10-14 10 views
35
Kod

:ucieczki .each {} iteracji wcześnie Ruby

c = 0 
items.each { |i| 
    puts i.to_s  
    # if c > 9 escape the each iteration early - and do not repeat 
    c++ 
} 

chcę złapać pierwsze 10 sztuk następnie pozostawić „każdego” pętlę.

Co mam zastąpić skomentowaną linią? czy istnieje lepsze podejście? coś więcej, idiomatyczny rubin?

+0

sugeruję odpowiedź nimrodm, że używa się: http://stackoverflow.com/questions/1568288/escaping-the-each-iteration-early-in-ruby/1568445#1568445 –

Odpowiedz

59

Podczas gdy rozwiązanie break działa, myślę, że bardziej funkcjonalne podejście naprawdę pasuje do tego problemu. Chcesz take pierwszych 10 elementów i wydrukować je więc spróbuj

items.take(10).each { |i| puts i.to_s } 
+0

Zawsze lubiłem FP, fajnie! – khelll

+14

Krótszy: 'puts items.take (10)' – Telemachus

+0

Próbowałem Googling dla "metoda ruby ​​wziąć" właśnie teraz i nie mogłem znaleźć odniesienia do modułu 'take' jest w. Gdzie jest to w API? –

1

Czy to wygląda tak, jak chcesz?

10.times { |i| 
    puts items[i].to_s 
} 
+0

Że będzie działać, ale nie zawsze będę pewien, że źródło ma co najmniej 10 pozycji. – BuddyJoe

+0

Ah. Możesz dodać 'break if items [i] == zero', ale w tym momencie' each_with_index' wygląda tak, jak powinno. –

42

Brak operatora ++ w języku Ruby. Konwencją jest również używanie do i end dla bloków wieloliniowych. Modyfikowanie plony rozwiązanie:

c = 0 
items.each do |i| 
    puts i.to_s  
    break if c > 9 
    c += 1 
end 

Albo też:

items.each_with_index do |i, c| 
    puts i.to_s  
    break if c > 9 
end 

Zobacz each_with_index a także Programming Ruby Break, Redo, and Next.

Aktualizacja:Chuck's answer z zakresów jest bardziej podobny do Ruby i nimrodm's answer użyciu take jest jeszcze lepiej.

+0

Dzięki. Odbierz i daj +1. Wow, byłem daleko od początkowej składni. – BuddyJoe

+0

Nie byłeś daleko, naprawdę: jedyną nieważną częścią twojej odpowiedzi było '++'. Kręcone szelki bloków będą działały, po prostu nie są preferowane w przypadku bloków wieloliniowych; zobacz http://stackoverflow.com/questions/533008/what-is-the-difference-or-value-of-these-block-coding-style-in-ruby –

+0

Podoba mi się twoje pierwsze rozwiązanie, bo jeśli chcesz zapętlić ponad 100 przedmiotów za każdym razem, ale tylko wyjąć 10 warunkowo można zwiększyć licznik niezależnie. – chrisallick

0
items.each_with_index { |i, c| puts i and break if c <= 9 } 
+0

To się zepsuje po pierwszym przedmiocie. – Chuck

+0

Niezupełnie, jak to przetestowałeś? – khelll

+0

@Khelll: czy to ze względu na leniwą ocenę 'i'? Działa, ale jest dla mnie trochę zbyt mądry. Mój mózg wciąż chce "> =" odkąd widzę "i zepsuje się, jeśli" razem. – Telemachus

7

break prace na ucieczkę z pętli wcześnie, ale to bardziej idiomatyczne po prostu zrobić items[0..9].each {|i| puts i}. (Jeśli wszystko, co robisz, to drukowanie elementów bez żadnych zmian, możesz po prostu zrobić puts items[0..9].)

+1

Napisałbym to jako: 'umieszcza przedmioty [0..9] .join (" \ n ")' –

4

Inny wariant:

puts items.first(10) 

Zauważ, że to działa dobrze z tablic mniej niż 10 elementów:

>> nums = (1..5).to_a 
=> [1, 2, 3, 4, 5] 
>> puts nums.first(10) 
1 
2 
3 
4 
5 

(Jeszcze jedna uwaga, wielu ludzi oferuje jakąś formę puts i.to_s, ale w takim przypadku nie jest ona automatycznie nadmiarowa? ? puts zadzwoń pod numer .to_s na ciąg znaków, aby go wydrukować, pomyślałem. musisz tylko .to_s jeśli chciał powiedzieć puts 'A' + i.to_s lub tym podobne).

3

Innym rozwiązaniem byłoby

items.first(10).each do |i| 
    puts i.to_s 
end 

To brzmi trochę łatwiej dla mnie niż łamanie na iteracyjnej, a pierwszy powróci tylko tyle elementów, ile jest dostępnych, jeśli nie ma ich wystarczająco dużo.

-1

Został on zapytał:

chcę złapać pierwsze 10 sztuk następnie pozostawić „każdego” pętlę.

Zastosowanie throw i catch do osiągnięcia tego celu, z nielicznymi zmianami w przykładzie:

catch(:done) do 
    c = 0 
    collected = [] 
    items.each do |item| 
     collected << item 
     throw(:done, collected) if c == 9 # started at 0 
     c += 1 
    end 
    collected # if the list is less than 10 long, return what was collected 
end 

Wystarczy throw etykieta :done z collected i catch który czeka na :done powróci collected.

I „Ruby” to się trochę:

catch(:done) do 
    items.inject([]) do |collected, item| 
     throw(:done, collected) if collected.size == 10 
     collected << item # collected gets returned here and populates the first argument of this block 
    end 
end 

nie wiem dlaczego niektórzy ludzie nie chcą używać inject i używać reduce zamiast (są równoważne), gdy wyraźnie pusta tablica podane do inject([]) jest wstrzyknięto item s! W każdym razie inject zwróci collected, jeśli jest mniej niż 10 elementów.

Większość odpowiedzi próbuje odpowiedzieć na pytanie, jaka może być intencja pytania, a nie pytanie, a items.take(10) ma w tym przypadku sens. Ale mogę sobie wyobrazić, że chcę pobrać pierwsze przedmioty, które pasują do mojego budżetu na 100 dolarów. Następnie można po prostu:

catch(:done) do 
    items.inject({items: [], budget: 100}) do |ledger, item| 
     remainder = ledger[:budget] - item.price 
     if remainder < 0 
      throw(:done, ledger) 
     else 
      ledger.tap do |this| 
       this[:items] << item 
       this[:budget] = remainder 
      end # tap just returns what is being tapped into, in this case, ledger 
     end 
    end 
end 
+0

Zrobiłeś proste pytanie i dałeś naprawdę skomplikowaną odpowiedź. Nie ma potrzeby używania "throw" i "catch" tutaj lub przekształcania go w 13 linii głęboko zagnieżdżonego kodu. Nie komplikuj. – NeuroXc

+0

Moja odpowiedź to 6 linii, pokazuje alternatywny sposób na ucieczkę z każdej zadanej pętli, jest zagnieżdżony o jeden poziom głębiej niż większość odpowiedzi. Moją nadzieją na pozostawienie tej odpowiedzi było pokazanie, jak alternatywnie wyjść z pętli, korzystając z tego prostego kontekstu. Jeśli rzeczywiście czytałeś mój post, moje 13 linii kodu jest bardziej złożoną odpowiedzią na bardziej złożony przykład, który przedstawiłem w mojej odpowiedzi. Z góry przepraszam za zbyt wiele słów w tej odpowiedzi. – Nothus