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 od1
do10
włącznie. Gdybyśmy chcieli, aby było to od1
do10
wyłączność, napisalibyśmy(1...10)
. -
.each
to.each
wyliczający, który wyliczaeach
element w obiekcie, na którym działa. W takim przypadku działa naeach
liczbę w zakresie. -
{ |i| puts i.even? ? 'even' : 'odd' }
to blok dlaeach
instrukcji, który sam może być dalej podzielony.-
|i|
oznacza to, że każdy element w zakresie jest reprezentowany w bloku przez identyfikatori
. -
puts
jest metodą wyjściową w Ruby, która ma automatyczny podział linii po każdym wydrukowaniu. (Możemy użyćprint
jeśli nie chcemy automatycznego dzielenia linii) -
i.even?
sprawdza, czyi
parzysty. 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]