Spis treściKliknij link, aby przejść do wybranego miejsca
Ta treść została automatycznie przetłumaczona z ukraińskiego.
Tablice to jedna z najwygodniejszych struktur danych w Ruby. Są elastyczne, dynamiczne i mają ogromną liczbę wbudowanych metod, które pozwalają na eleganckie przetwarzanie danych. Przyjrzyjmy się głównym z nich na przykładach.
each - prosty przebieg elementów
Metoda each iteruje tablicę i wykonuje blok kodu dla każdego elementu. Zwykle używa się jej, gdy trzeba coś zrobić z elementami, ale nie tworzyć nowej tablicy.
[1, 2, 3, 4, 5].each do |n|
puts "Liczba: #{n}"
end
Wynik:
Liczba: 1 Liczba: 2 Liczba: 3 Liczba: 4 Liczba: 5 => [1, 2, 3, 4, 5]
each zawsze zwraca oryginalną tablicę, a nie wynik wykonania bloku. Co to oznacza? Blok wykonuje puts (widzisz wydrukowane "Liczba 1" i tak dalej). A iterator zwraca tablicę => [1, 2, 3, 4, 5]
Oznacza to, że jeśli przekażemy wartość iteratora do zmiennej - otrzymamy tablicę.
myvar = [1, 2, 3, 4, 5].each do |n|
puts "Liczba: #{n}"
end
Liczba: 1
Liczba: 2
Liczba: 3
Liczba: 4
Liczba: 5
=> [1, 2, 3, 4, 5]
myvar
=> [1, 2, 3, 4, 5]
map - transformacja elementów
Metoda map (lub collect) tworzy nową tablicę, w której każdy element to wynik wykonania bloku.
numbers = [1, 2, 3, 4, 5]
squares = numbers.map { |n| n ** 2 }
p squares # => [1, 4, 9, 16, 25]
Używaj map, gdy potrzebujesz uzyskać nowy zestaw danych z istniejącej tablicy.
Jakie są różnice między map a collect?
W Ruby map jest po prostu bardziej znaną nazwą dla programistów, którzy przyszli z innych języków (JavaScript, Python itd.). A collect to historyczna nazwa, która pozostała z wczesnych wersji Ruby (pod wpływem Smalltalk).
Jeśli spojrzeć na kod Ruby (moduł Enumerable):
alias collect map
czyli to dokładny synonim, nie opakowanie, nie delegat - po prostu inna nazwa tej samej metody.
select - filtrowanie elementów
Metoda select zwraca tablicę elementów, dla których blok zwraca true.
numbers = [1, 2, 3, 4, 5]
even_numbers = numbers.select { |n| n.even? }
p even_numbers # => [2, 4]
Istnieje metoda odwrotna - reject, która zwraca elementy, dla których blok zwraca false.
odd_numbers = numbers.reject { |n| n.even? }
p odd_numbers # => [1, 3, 5]
inject / reduce - akumulacja wartości
inject (synonim reduce) to potężne narzędzie do "zwiń" tablicę w jedną wartość. Można policzyć sumę, zbudować hasz itd.
numbers = [1, 2, 3, 4, 5]
sum = numbers.inject(0) { |acc, n| acc + n }
p sum # => 15
Przyjmuje wartość początkową (w naszym przypadku 0) i przekazuje ją razem z każdym elementem tablicy do bloku.
Składnia:
array.inject(initial_value) { |accumulator, element| ... }
- accumulator - zmienna, w której przechowywany jest bieżący wynik.
- element - bieżący element tablicy.
- Blok zwraca nową wartość dla accumulator.
Jeszcze jeden przykład - połączenie elementów w ciąg (string):
words = ["Ruby", "jest", "fajne"]
sentence = words.reduce("") { |acc, word| acc + word + " " }
p sentence.strip # => "Ruby jest fajne"
strip użyto, aby usunąć zbędną spację na końcu.
Budowa haszu będzie wyglądać tak:
letters = %w[a b c]
indexed = letters.inject({}) { |acc, l| acc[l] = l.upcase; acc }
# => {"a"=>"A", "b"=>"B", "c"=>"C"}
Jednak tutaj jest trochę trudniej. Metoda inject (lub reduce) przechodzi przez kolekcję i stopniowo akumuluje wynik w akumulatorze (acc).
Przekazujemy {} - czyli wartość początkową akumulatora - pusty hasz.
{ |acc, l| acc[l] = l.upcase; acc }
To blok, który jest wywoływany dla każdego elementu l w tablicy.
- acc - to bieżący akumulator (na początku {})
- l - bieżąca litera ("a", potem "b", potem "c")
Wewnątrz bloku:
acc[l] = l.upcase
dodaje do hasza parę:
- klucz: l (na przykład "a")
- wartość: l.upcase (czyli "A")
Po tym zwracamy sam acc, aby przekazać go do następnej iteracji
Oczywiście można to zrobić w inny sposób, ale tutaj rozważamy możliwości tych metod.
filter_map - magia Ruby 2.7+
Metoda filter_map łączy map i select w jednym przebiegu tablicy. Przekształca i filtrowa jednocześnie.
numbers = [1, 2, 3, 4, 5, 6]
even_squares = numbers.filter_map { |n| n**2 if n.even? }
p even_squares # => [4, 16, 36]
To wygodniejsze i bardziej efektywne niż numbers.select { ... }.map { ... }.
Ten post nie ma jeszcze żadnych dodatków od autora.