Funkcja map() Pythona, wyjaśniona przykładami

W tym opracowaniu zgłębisz tajniki wykorzystania funkcji map() w języku Python, która umożliwia zastosowanie określonej operacji do każdego elementu w zbiorze danych.

Python, jako język wspierający paradygmat programowania funkcyjnego, umożliwia definiowanie zadań poprzez operacje na funkcjach. Funkcje w Pythonie są traktowane jak obiekty, co oznacza, że mogą być przekazywane jako argumenty do innych funkcji, a także zwracane jako wyniki.

Funkcja map() jest narzędziem, które przyjmuje inną funkcję jako argument i aplikuje ją do każdego elementu w sekwencji, zbiorze lub innej strukturze iterowalnej.

Po lekturze tego przewodnika, będziesz w stanie wykorzystać potencjał map() w Pythonie do zastępowania tradycyjnych pętli oraz konstrukcji list składanych. Prześledzimy praktyczne przykłady, aby zrozumieć różne zastosowania tej funkcji.

Jak zaaplikować funkcję do elementów listy w Pythonie?

Rozpocznijmy od analizy konkretnego przypadku. 👩‍🏫

Załóżmy, że mamy listę liczb, którą nazwiemy nums.

nums = [2,4,3,7]

Następnie, zdefiniujmy funkcję self_pow(). Ta funkcja, przyjmując liczbę jako argument, zwróci jej wartość podniesioną do potęgi samej siebie, czyli n**n.

W Pythonie operator potęgowania to **. Wyrażenie a**b oznacza a podniesione do potęgi b, czyli ab.

def self_pow(n):
  return n**n

ZADANIE: Stworzenie nowej listy, nums_pow, która będzie zawierać wyniki zastosowania funkcji self_pow() do każdego elementu listy nums.

Wykorzystanie pętli

Aby to osiągnąć, można użyć pętli for w Pythonie:

  • Dla każdej liczby w liście nums, wywołaj funkcję self_pow() z tą liczbą jako argumentem.
  • Dodaj wynik wywołania funkcji do nowej listy nums_pow.
nums_pow = []

for num in nums:
  nums_pow.append(self_pow(num))

print(nums_pow)

W rezultacie, każda liczba w nums zostanie podniesiona do potęgi samej siebie. Elementy listy nums_pow będą zatem: 22, 44, 33, 77.

Output
[4, 256, 27, 823543]

Wykorzystanie list składanych

Możemy osiągnąć ten sam efekt bardziej zwięźle, stosując konstrukcję list składanych. Analizując powyższą pętlę for, możemy wyodrębnić wyrażenie wyjściowe oraz listę, po której iterujemy.

Możemy zapisać ogólną konstrukcję listową jako:

new_list = [<wyrażenie wyjściowe> for item in iterable]

W kontekście generowania listy nums_pow, wyrażenie listowe będzie wyglądało następująco:

nums_pow = [self_pow(num) for num in nums]
print(nums_pow)

Oczekiwany wynik, analogiczny do tego z pętlą for, zostanie wygenerowany.

Output
[4, 256, 27, 823543]

Alternatywą dla pętli i list składanych jest funkcja map() w Pythonie. Charakteryzuje się ona zwięzłą składnią i ułatwia aplikowanie funkcji do wszystkich elementów struktury iterowalnej. Przejdźmy do analizy składni tej funkcji.

Składnia funkcji map() w Pythonie

Ogólna forma funkcji map() prezentuje się następująco:

map(funkcja, iterowalny_1,[iterowalny_2,...,iterowalny_n])

Funkcja map() przyjmuje co najmniej dwa parametry: funkcję oraz element iterowalny.

W powyższej konstrukcji:

  • funkcja oznacza dowolną funkcję Pythona, w tym funkcje wbudowane, zdefiniowane przez użytkownika, klasy, instancje klas, metody oraz wiele innych obiektów wywoływalnych.
  • iterowalny to dowolna struktura iterowalna w Pythonie, na przykład lista, krotka, czy ciąg znaków.
  • Działanie funkcji map() polega na zastosowaniu podanej funkcji do każdego elementu w strukturze iterowalnej.

Co zwraca funkcja map()?

Zwraca ona obiekt mapy. Możesz następnie przekształcić ten obiekt w listę za pomocą konstrukcji: list(map(funkcja, iterowalny)).

W zależności od potrzeb, obiekt mapy może zostać przekształcony w krotkę.

Teraz, gdy znasz już składnię funkcji map(), przejdźmy do praktycznych przykładów.

Dla celów tego tutoriala, zalecane jest posiadanie zainstalowanej wersji Pythona 3.x. Alternatywnie, kod można uruchamiać w internetowym edytorze Pythona newsblog.pl.

Jak używać funkcji map() z funkcjami zdefiniowanymi przez użytkownika?

#1. Wcześniej wykorzystywaliśmy funkcję self_pow() dla każdej liczby w liście nums. Wykorzystując składnię funkcji map(), możemy przekazać funkcję self_pow oraz elementy listy nums jako argumenty.

Uwaga: Podajemy tylko nazwę funkcji, a nie jej wywołanie. Użyj self_pow, a nie self_pow().

Funkcja map() zwróci obiekt mapy.

print(map(self_pow,nums))

<map object at 0x7f7d315c14d0>

Następnie, obiekt mapy możemy przekształcić w listę za pomocą funkcji list(), jak widać poniżej.

nums_pow = list(map(self_pow,nums))
print(nums_pow)

Oto wynik, gdzie każdy element num z listy nums został przekształcony na numnum w liście nums_pow.

Output
[4, 256, 27, 823543]

#2. Rozważmy funkcję inch_to_cm(), która dokonuje konwersji cali na centymetry. 1 cal = 2.54 cm.

def inch_to_cm(inch):
  return inch*2.54

Aby dokonać konwersji wartości cali z listy na centymetry, użyjemy funkcji map(), jak przedstawiono w poniższym fragmencie kodu.

inches = [5.54,3.4,1,25,8.2]
cms = list(map(inch_to_cm,inches))
print(cms)

Lista cms zawiera wartości z listy inches, wyrażone w centymetrach.

Output
[14.0716, 8.636, 2.54, 63.5, 20.828]

Jak wykorzystać funkcję map() z wbudowanymi funkcjami?

W tej sekcji, zapoznamy się z wykorzystaniem funkcji map() w połączeniu z wbudowanymi funkcjami Pythona.

#1. Załóżmy, że mamy listę strings, zawierającą nazwy języków programowania. Chcemy utworzyć nową listę, strings_upper, w której wszystkie nazwy będą zapisane wielkimi literami.

strings = ['JavaScript','Rust','Python','Go']

Wbudowana metoda łańcuchowa .upper(), zastosowana do łańcucha znaków, zwraca jego kopię zapisaną wielkimi literami.

strings_upper = list(map(str.upper,strings)) 
print(strings_upper)

Lista strings_upper zawiera łańcuchy znaków z listy strings, sformatowane wielkimi literami.

Output
['JAVASCRIPT', 'RUST', 'PYTHON', 'GO']

#2. Wbudowana funkcja len() w Pythonie przyjmuje sekwencję jako argument i zwraca jej długość. Aby określić długość każdego łańcucha w liście strings, możemy zastosować funkcję map(), wywołując funkcję len na każdym z łańcuchów, jak poniżej.

strings_len = list(map(len,strings))
print(strings_len)
Output
[10, 4, 6, 2]

#3. Funkcję map() możemy stosować również z innymi kolekcjami, na przykład z krotkami.

Poniższy przykład przedstawia krotkę zawierającą informacje o liczbie sypialni, powierzchni i mieście, w którym znajduje się nieruchomość.

W Pythonie funkcja type() zwraca typ danych dowolnego obiektu. Aby poznać typ danych każdego elementu w krotce, można zastosować funkcję map(), wywołując type na każdym elemencie krotki.

house = (2,758.5,'Bangalore')
house_elt_type = tuple(map(type,house))
print(house_elt_type)

Obiekt mapy został rzutowany na krotkę. Możliwe jest również rzutowanie na listę, bądź inną kolekcję.

W poniższym wyniku, widzimy, że typy danych dla wartości 2, 758.5 oraz 'Bangalore’ zostały prawidłowo rozpoznane jako 'int’, 'float’ i 'str’.

Output
(<class 'int'>, <class 'float'>, <class 'str'>)

#4. W Pythonie, możliwe jest importowanie wbudowanych modułów i używanie funkcji w nich zdefiniowanych.

Aby obliczyć pierwiastek kwadratowy każdej liczby w liście nums, możemy wykorzystać funkcję sqrt z modułu math.

import math
nums = [30,90,34,45,97]
nums_sqrt = list(map(math.sqrt,nums))
print(nums_sqrt)
Output
[5.477225575051661, 9.486832980505138, 5.830951894845301, 6.708203932499369, 9.848857801796104]

Powyższe dane wyjściowe są trudne w analizie i interpretacji. Może okazać się konieczne zaokrąglenie każdej wartości pierwiastka kwadratowego do dwóch miejsc po przecinku.

Jak zaokrąglić liczbę zmiennoprzecinkową w Pythonie?

Zdefiniujmy funkcję round_2(), która przyjmuje liczbę zmiennoprzecinkową jako argument i zaokrągla ją do dwóch miejsc po przecinku.

def round_2(num):
  return round(num,2)

Teraz, możemy wykorzystać funkcję map() w połączeniu z round_2 i nums_sqrt.

nums_sqrt_round = list(map(round_2,nums_sqrt))
print(nums_sqrt_round)
Output
[5.48, 9.49, 5.83, 6.71, 9.85]

Możliwe jest również użycie zagnieżdżonych funkcji map(), gdzie wewnętrzna map służy do obliczania pierwiastków kwadratowych (nums_sqrt), a zewnętrzna map realizuje operację zaokrąglania.

nums_sqrt_round = list(map(round_2,list(map(math.sqrt,nums))))
print(nums_sqrt_round)
Output
[5.48, 9.49, 5.83, 6.71, 9.85]

Wyniki obu podejść są identyczne. Należy jednak zadbać o czytelność i łatwość utrzymania kodu podczas zagnieżdżania funkcji, jak przedstawiono powyżej.

Jak używać funkcji map() z funkcjami lambda

W poprzednich rozdziałach, nauczyliśmy się używać funkcji map() w Pythonie z funkcjami wbudowanymi oraz zdefiniowanymi przez użytkownika. Teraz dowiemy się, jak wykorzystać funkcję map() z funkcjami lambda, które w Pythonie są anonimowe.

W sytuacjach, gdy ciało funkcji składa się tylko z jednej linii kodu i potrzebujemy jej użyć tylko raz, bez odwoływania się do niej w innych częściach programu, możemy zdefiniować ją jako funkcję lambda.

Uwaga: lambda argumenty: wyrażenie to ogólna składnia definiowania funkcji lambda w Pythonie.

#1. Rozważmy listę łańcuchów znaków. Chcemy uzyskać nową listę, strings_rev, w której łańcuchy znaków będą odwrócone.

strings = ['JavaScript','Rust','Python','Go']

Możemy odwrócić łańcuch znaków w Pythonie, stosując technikę krojenia łańcuchów (ang. string slicing).

Uwaga: Jest to ogólna forma wyrażenia krojącego łańcuch str[start:stop:step].

– Jeżeli wartości start i stop nie są zdefiniowane, wycinek zaczyna się na początku łańcucha i kończy na jego końcu.
– Ujemne wartości kroku (step) powodują, że wycinek tworzony jest od końca łańcucha.
– Dlatego wyrażenie str[::-1] zwraca odwróconą kopię str.

Możemy użyć funkcji lambda: lambda x:x[::-1], wewnątrz funkcji map, jak przedstawiono poniżej.

strings_rev = list(map(lambda x:x[::-1],strings))
print(strings_rev)

Podobnie jak w innych przykładach, obiekt mapy jest przekształcany na listę. W wyniku, każdy łańcuch z listy strings zostaje odwrócony.

Output
['tpircSavaJ', 'tsuR', 'nohtyP', 'oG']

#2. W poprzedniej sekcji, obliczaliśmy pierwiastek kwadratowy każdej liczby z listy, a następnie zaokrąglaliśmy wyniki do dwóch miejsc po przecinku.

W tym celu, używaliśmy funkcji round_2(). Przekształćmy teraz funkcję round_2() w funkcję lambda i zastosujmy ją w połączeniu z funkcją map(), jak niżej.

nums_sqrt_round_l =list(map(lambda num:round(num,2),nums_sqrt))
print(nums_sqrt_round_l)

Jak widzimy, uzyskany wynik jest identyczny z tym, który otrzymaliśmy przy użyciu funkcji round_2().

Output
[5.48, 9.49, 5.83, 6.71, 9.85]

Jak używać funkcji map() z wieloma elementami iterowalnymi?

W omawianych dotychczas przykładach, funkcja była aplikowana do elementów tylko jednej struktury iterowalnej.

Czasami, możemy mieć funkcje, które przyjmują dwa, lub więcej argumentów. W takich przypadkach, każdy z argumentów przechowywany jest na oddzielnej liście, lub w innej podobnej kolekcji.

Możemy również używać funkcji map() w Pythonie z wieloma listami.

#1. Rozważmy funkcję area(), która przyjmuje długość i szerokość jako argumenty, i zwraca pole powierzchni, czyli długość * szerokość.

def area(length,breadth):
  return length*breadth

Długości i szerokości różnych prostokątów przechowywane są w dwóch odrębnych listach, odpowiednio lengths i breadths.

lengths = [4,8,10,18]
breadths = [9,4,6,11]

Możemy użyć funkcji map(), aby zastosować funkcję area do powyższych list, przekazując obie listy lengths i breadths.

areas = list(map(area,lengths,breadths))
print(areas)

Ponieważ funkcja area przyjmuje dwa argumenty, wartości z list lengths i breadths będą traktowane jako argumenty funkcji.

Output
[36, 32, 60, 198]

#2. Moduł matematyczny Pythona posiada funkcję log, która pozwala nam obliczyć logarytm liczby o dowolnej podstawie.

Uwaga: log(x, podstawa) zwraca wartość logarytmu liczby x o podstawie zdefiniowanej przez podstawa. Jeżeli podstawa nie jest zdefiniowana, domyślną wartością jest e (logarytm naturalny).

W tym przykładzie:

  • Lista x zawiera wartości, dla których chcemy obliczyć logarytm.
  • Lista base zawiera wartości podstaw, które mają być użyte w obliczeniach logarytmicznych.
x = [2,6,12,10]
base = [2,3,2,5]

Możemy użyć funkcji map() z math.log oraz listami x i base, aby utworzyć nową listę log_x.

log_x = list(map(math.log,x,base))
print(log_x)

Oto rezultat.

Output
[1.0, 1.6309297535714573, 3.5849625007211565, 1.4306765580733933]

Podsumowanie

Poniżej znajduje się podsumowanie kluczowych punktów, które poznałeś w tym samouczku:

  • Funkcja map() w Pythonie przyjmuje co najmniej dwa argumenty: funkcję i iterowalną strukturę danych, zgodnie ze składnią map(funkcja, iterowalny(e)).
  • funkcja może być dowolnym obiektem wywoływalnym w Pythonie.
  • Gdy funkcja przyjmuje k argumentów, można użyć map() z funkcją oraz k elementami iterowalnymi.

Następnym krokiem będzie nauka pracy ze zbiorami danych w Pythonie.