W tym zadaniu, które rozwiążemy na kilka sposobów, musimy stworzyć funkcję, która przyjmie tekst i zwróci nam ilość samogłosek „aeiou” (samogłoski w języku angielskim) w tym tekście.
Czyli tak – funkcja ma za zadanie przyjąć tekst i zwrócić liczbę, która oznacza ilość jakichkolwiek liter w zbiorze „aeiou”.
Sposób 1 – pętla for, pętla while
Do tego użyć możemy pętli for, która przejdzie po każdej literze napisu i sprawdzi, czy dana litera znajduje się w „aeiou”, jeżeli tak, licznik (początkowo ustawiony na 0) zwiększy o 1, na koniec ten licznik zwróci.
def num_vovels(text):
num = 0
for letter in text:
if letter in "aeiou":
num += 1
return num
print(num_vovels("aaab")) #3
print(num_vovels("hello")) #2
print(num_vovels("aeiouxx")) #5
Dokładnie z tym mamy tutaj miejsce. Funkcja przyjmuje argument text, licznik num ustawiony początkowo na 0, dla każdej litery w text sprawdzamy, czy ta litera to samogłoska, jeżeli tak zwiększamy licznik o 1. Po wykonaniu pętli – zwracamy licznik.
Można oczywiście zastosować pętlę while, choć będzie się to wiązało z wprowadzeniem nowej zmiennej, robiącej za indeks do przechodzenia po tekście:
def num_vovels(text):
num = 0
idx = 0
while idx < len(text):
if text[idx] in "aeiou":
num += 1
idx += 1
return num
print(num_vovels("aaab")) #3
print(num_vovels("hello")) #2
print(num_vovels("aeiouxx")) #5
Czyli tak – tekst o długości np. 5 ma index pierwszy 0 i index ostatni 4. A zatem tworzymy zmienną idx, równą 0 i stawiamy warunek – „tak długo jak ta zmienna idx jest mniejsza niż długość tekstu” (bo wiemy, że ostatni indeks jest o 1 mniejszy niż długość).
Przy tak postawionym warunku sprawdzamy zawartość text pod danym indeksem (zaczynając od 0), czy się znajduje w „aeiou”, jeżeli tak, zwiększamy num, niezależnie od tego zwiększamy idx (aby w następnym obrocie pętli móc sprawdzić element następny i tak aż do momentu, w którym idx przestanie być mniejsze niż długość tekstu).
Może i nieco bardziej skomplikowana logika, ale koniec końców cel osiągnięty, zadanie wykonane, przy użyciu pętli.
Sposób 2 – dziwne podejście
Zawsze możemy zastosować coś dziwnego. I tak się czasem robi. Ten sposób nie jest szczególnie mądry, ale czasami takie myślenie się przydaje, więc podam go tu.
Wymyślmy sobie jakiś znak, którego w naszym tekście – naszym zdaniem – nie ma prawa być. Załóżmy, że pracujemy z tekstem, w którym, z powodów bezpieczeństwa znak # i tak się nie znajdzie, bo jest odfiltrowywany, aby zapobiec atakowi SQL Injection (całkiem realny scenariusz). Albo jakiś inny filtr sprawia, że tego znaku tam nie ma, został odfiltrowany.
A skoro tak, możemy go sobie użyć.
def num_vovels(text):
text = text.replace("a", "#")
text = text.replace("e", "#")
text = text.replace("i", "#")
text = text.replace("o", "#")
text = text.replace("u", "#")
return text.count("#")
print(num_vovels("aaab")) #3
print(num_vovels("hello")) #2
print(num_vovels("aeiouxx")) #5
W tym osobliwym podejściu my zamieniamy każdą samogłoskę na znak #, następnie zwracamy ilość wystąpień „#” w naszym tekście. Dziwne? Ale działa. Czy są problemy? Cóż, jeżeli założymy, że tekst, który dostaniemy nie ma prawa mieć już w sobie jakichś znaków „#”, które nam to liczenie popsuć mogą – to nie ma żadnych.
No może kwestia powtarzania się, oraz kwestia wielkich liter. A zatem:
def num_vovels(text):
for letter in "aeiouAEIOU":
text = text.replace(letter, "#")
return text.count("#")
print(num_vovels("Aaab")) #3
print(num_vovels("hello")) #2
print(num_vovels("Aeiouxx")) #5
Tutaj w pętli przechodzimy po małych i wielkich samogłoskach i każdą zamieniamy na znak „#”, zwracamy ilość wystąpień tego znaku.
A jak rozwiązać problem małych i wielkich liter w naszym poprzednim przykładzie?
Albo tak, porównując literę z małymi i dużymi samogłoskami:
def num_vovels(text):
num = 0
for letter in text:
if letter in "aeiouAEIOU":
num += 1
return num
print(num_vovels("Aaab")) #3
print(num_vovels("hello")) #2
print(num_vovels("Aeiouxx")) #5
Albo porównując literę, co do której upewnimy się, że została sprowadzona do małej:
def num_vovels(text):
num = 0
for letter in text:
if letter.lower() in "aeiou":
num += 1
return num
print(num_vovels("Aaab")) #3
print(num_vovels("hello")) #2
print(num_vovels("Aeiouxx")) #5
Sposób 3 – filtrowanie
Postarajmy się zamienić nasz napis na listę i odfiltrować z niego wszystko, co samogłoską nie jest. Na razie, dla zobrazowania:
msg ="abceiou"
lst = list(msg)
print(lst)
#['a', 'b', 'c', 'e', 'i', 'o', 'u']
lst = list(filter(lambda x: x in "aeiou", lst))
print(lst)
#['a', 'e', 'i', 'o', 'u']
print(len(lst))
#5
Czyli mamy nasz napis. Zamieniamy go na listę. Każda litera – nowy element listy. Następnie mamy zamieniony na listę obiekt filter. Co on robi?
Przyjmuje argument x i sprawdza, czy x jest w „aeiou” i filtruje na liście lst. Wypisujemy lst, mamy odfiltrowane nie-samogłoski. Możemy też długość tej listy wypisać i mamy ich ilość.
Mamy zatem wszystkie elementy, których potrzebujemy do budowy naszej funkcji:
def num_vovels(text):
text_lst = list(text)
text_lst = list(filter(lambda x: x in "aeiou", text_lst))
return len(text_lst)
print(num_vovels("aaab")) #3
print(num_vovels("hello")) #2
print(num_vovels("aeiouxx")) #5
To teraz jeszcze, aby dla wielkich liter działało. Proponuję filtrować te elementy, które zapisane małą literą, znajdowałyby się w „aeiou”:
def num_vovels(text):
text_lst = list(text)
text_lst = list(filter(lambda x: x.lower() in "aeiou", text_lst))
return len(text_lst)
print(num_vovels("Aaab")) #3
print(num_vovels("hello")) #2
print(num_vovels("Aeiouxx")) #5
Sposób 4 – filtrowanie przez list comprehension
Zobaczmy na ten, nie taki do końca czytelny kod z poprzedniego przykładu, który używał filter:
def num_vovels(text):
text_lst = list(text)
text_lst = list(filter(lambda x: x.lower() in "aeiou", text_lst))
return len(text_lst)
print(num_vovels("Aaab")) #3
print(num_vovels("hello")) #2
print(num_vovels("Aeiouxx")) #5
Zarówno zamienienie tekstu na listę, jak i odfiltrowanie z niego czegoś, możemy zapisać przy użyciu list comprehension:
msg = "abceiou"
print([char for char in msg])
#['a', 'b', 'c', 'e', 'i', 'o', 'u']
print([char for char in msg if char.lower() in "aeiou"])
#['a', 'e', 'i', 'o', 'u']
A zatem wersja dłuższa:
def num_vovels(text):
text_lst = [char for char in text]
text_lst = [el for el in text_lst if el.lower() in "aeiou"]
return len(text_lst)
print(num_vovels("Aaab")) #3
print(num_vovels("hello")) #2
print(num_vovels("Aeiouxx")) #5
Tutaj, zupełnie niepotrzebnie, osobno kopiujemy litery z tekstu do listy i w osobnej linijce filtrujemy te elementy, które zapisane małą literą nie znajdują się w „aeiou”. Można to oczywiście skrócić i wersja skrócona będzie akurat dużo czytelniejsza:
def num_vovels(text):
text_lst = [char for char in text if char.lower() in "aeiou"]
return len(text_lst)
print(num_vovels("Aaab")) #3
print(num_vovels("hello")) #2
print(num_vovels("Aeiouxx")) #5
Czyli tak, zapisz do listy znak dla każdego znaku w text jeżeli znak, zapisany małą literą, mieści się w zbiorze znaków „aeiou”. Zwróć długość tej listy.
Czy można jeszcze krócej? Można:
def num_vovels(text):
return len([char for char in text if char.lower() in "aeiou"])
print(num_vovels("Aaab")) #3
print(num_vovels("hello")) #2
print(num_vovels("Aeiouxx")) #5
Sposobów na wykonanie tego zadanie jest zresztą dużo więcej. Podałem 4 najbardziej logiczne.