Ruby Language
Iteracja
Szukaj…
Każdy
Ruby ma wiele typów modułów wyliczających, ale each z each jest pierwszym i najprostszym typem modułu wyliczającego. Wydrukujemy even lub odd dla każdej liczby od 1 do 10 aby pokazać, jak działa each .
Zasadniczo istnieją dwa sposoby przekazywania tak zwanych blocks . block jest przekazywanym fragmentem kodu, który zostanie wykonany za pomocą wywoływanej metody. each metoda pobiera block który wywołuje dla każdego elementu kolekcji obiektów, do których została wywołana.
Istnieją dwa sposoby przekazania bloku do metody:
Metoda 1: Inline
(1..10).each { |i| puts i.even? ? 'even' : 'odd' }
Jest to bardzo skompresowany i rubinowy sposób rozwiązania tego problemu. Podzielmy to kawałek po kawałku.
-
(1..10)to zakres od1do10włącznie. Gdybyśmy chcieli, aby było to od1do10wyłączność, napisalibyśmy(1...10). -
.eachto.eachwyliczający, który wyliczaeachelement w obiekcie, na którym działa. W takim przypadku działa naeachliczbę w zakresie. -
{ |i| puts i.even? ? 'even' : 'odd' }to blok dlaeachinstrukcji, który sam może być dalej podzielony.-
|i|oznacza to, że każdy element w zakresie jest reprezentowany w bloku przez identyfikatori. -
putsjest metodą wyjściową w Ruby, która ma automatyczny podział linii po każdym wydrukowaniu. (Możemy użyćprintjeśli nie chcemy automatycznego dzielenia linii) -
i.even?sprawdza, czyiparzysty. Mogliśmy również użyći % 2 == 0; jednak lepiej jest korzystać z wbudowanych metod. -
? "even" : "odd"to trójskładnikowy operator Ruby. Sposób konstruowania operatora trójskładnikowego toexpression ? a : b. To jest skrót od
if expression a else b end
-
W przypadku kodu dłuższego niż jedna linia block powinien zostać przekazany jako multiline block .
Metoda 2: Wielowierszowa
(1..10).each do |i|
if i.even?
puts 'even'
else
puts 'odd'
end
end
W multiline block do zastępuje nawias otwierający, a end zastępuje nawias zamykający ze stylu inline .
Ruby obsługuje również reverse_each. Powtórzy tablicę do tyłu.
@arr = [1,2,3,4]
puts @arr.inspect # output is [1,2,3,4]
print "Reversed array elements["
@arr.reverse_each do |val|
print " #{val} " # output is 4 3 2 1
end
print "]\n"
Implementacja w klasie
Enumerable to najpopularniejszy moduł w Rubim. Jego celem jest dostarczenie iterowalnych metod, takich jak map , select , reduce itp. Klasy, które używają Enumerable obejmują Array , Hash , Range . Aby z niego skorzystać, musisz include Enumerable i zaimplementować each .
class NaturalNumbers
include Enumerable
def initialize(upper_limit)
@upper_limit = upper_limit
end
def each(&block)
0.upto(@upper_limit).each(&block)
end
end
n = NaturalNumbers.new(6)
n.reduce(:+) # => 21
n.select(&:even?) # => [0, 2, 4, 6]
n.map { |number| number ** 2 } # => [0, 1, 4, 9, 16, 25, 36]
Mapa
Zwraca zmieniony obiekt, ale oryginalny obiekt pozostaje niezmieniony. Na przykład:
arr = [1, 2, 3]
arr.map { |i| i + 1 } # => [2, 3, 4]
arr # => [1, 2, 3]
map! zmienia oryginalny obiekt:
arr = [1, 2, 3]
arr.map! { |i| i + 1 } # => [2, 3, 4]
arr # => [2, 3, 4]
Uwaga: możesz także użyć opcji collect aby zrobić to samo.
Iterowanie po złożonych obiektach
Tablice
Możesz iterować po zagnieżdżonych tablicach:
[[1, 2], [3, 4]].each { |(a, b)| p "a: #{ a }", "b: #{ b }" }
Dozwolona jest również następująca składnia:
[[1, 2], [3, 4]].each { |a, b| "a: #{ a }", "b: #{ b }" }
Będzie produkować:
"a: 1"
"b: 2"
"a: 3"
"b: 4"
Hashes
Możesz iterować po parach klucz-wartość:
{a: 1, b: 2, c: 3}.each { |pair| p "pair: #{ pair }" }
Będzie produkować:
"pair: [:a, 1]"
"pair: [:b, 2]"
"pair: [:c, 3]"
Możesz iterować klucze i wartości jednocześnie:
{a: 1, b: 2, c: 3}.each { |(k, v)| p "k: #{ k }", "v: #{ k }" }
Będzie produkować:
"k: a"
"v: a"
"k: b"
"v: b"
"k: c"
"v: c"
Dla iteratora
Powtarza się od 4 do 13 (włącznie).
for i in 4..13
puts "this is #{i}.th number"
end
Możemy również iterować tablice za pomocą for
names = ['Siva', 'Charan', 'Naresh', 'Manish']
for name in names
puts name
end
Iteracja z indeksem
Czasami chcesz poznać pozycję ( indeks ) bieżącego elementu podczas iteracji po module wyliczającym. W tym celu Ruby udostępnia metodę with_index . Można go zastosować do wszystkich modułów wyliczających. Zasadniczo, dodając with_index do wyliczenia, można wyliczyć to wyliczenie. Indeks jest przekazywany do bloku jako drugi argument.
[2,3,4].map.with_index { |e, i| puts "Element of array number #{i} => #{e}" }
#Element of array number 0 => 2
#Element of array number 1 => 3
#Element of array number 2 => 4
#=> [nil, nil, nil]
with_index ma opcjonalny argument - pierwszy indeks, który domyślnie ma wartość 0 :
[2,3,4].map.with_index(1) { |e, i| puts "Element of array number #{i} => #{e}" }
#Element of array number 1 => 2
#Element of array number 2 => 3
#Element of array number 3 => 4
#=> [nil, nil, nil]
Istnieje specjalna metoda each_with_index . Jedyna różnica między nim a każdym z nich. Z each.with_index polega na tym, że nie można przekazać argumentu, więc pierwszy indeks ma wartość 0 cały czas.
[2,3,4].each_with_index { |e, i| puts "Element of array number #{i} => #{e}" }
#Element of array number 0 => 2
#Element of array number 1 => 3
#Element of array number 2 => 4
#=> [2, 3, 4]