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.