Listy


Teoria
Instrukcje

Charakterystyka list w Pythonie

Lista (list) w Pythonie cechuje się trzema podstawowymi charakterystykami:
  • jest tzw. container sequence, czyli może przechowywać elementy różnego typu, np. liczbę całkowitą, zmiennoprzecinkową, ciąg znaków i bajty w jednej liście (przykład poniżej). Jednak w praktyce najczęściej i tak w liście trzyma się raczej tylko elementy jednego typu.
    items = ["bmw", 1, 2.0, b'0xAF']
  • jest strukturą mutowalną, czyli możemy do niej elementy dodawać, odejmować, zmieniać ich wartość lub kolejność itp. bez tworzenia nowego obiektu, gwarantuje nam zachowanie kolejności elementów, w jakiej zostały one dodane do listy (chyba że sami jawnie zmienimy ich kolejność, np. w wyniku sortowania czy odwrócenia listy).
  • Lista nie przechowuje wartości swoich elementów fizycznie w obrębie swojej przestrzeni w pamięci (w przeciwieństwie, na przykład, do sekwencji bytes czy array), a jedynie posiada referencję do każdego z obiektów, będących jej elementami.

    nicjalizacja

    Listę tworzymy używając tzw. literału listy, czyli po prostu nawiasów kwadratowych: [ ], w środku podając kolejne elementy po przecinku:
    cars = ["bmw", "audi", "mercedes", "toyota", "nissan"]

    Dostepne metody:

  • append — dodaje element na koniec listy. Równowaznie: l+=[x].
  • remove — usuwa pierwsze wystapienie danej wartosci. Zwraca bład, jeżeli jej nie znajdzie.
  • pop — pobiera wartość z danego indeksu i usuwa ja z listy. Domyslna wartosc indeksu: -1.
  • insert — wstawia wartość na miejsce o indeksie podanym w jej drugim argumencie, przesuwajac dalsze wartosci o jeden.
    Równowaznie: l=l[:i]+[a]+l[i:].
  • len - Sprawdzenie długości listy --> len(nazwa_listy)
  • type - sprawdzenie czy zmienna jest listą --> typoe(zmienna)



  • Ćwiczenia z rozwiązaniami
    Wykonaj następujące cwiczenia

    Podstawowe operacje na listach


    Tworzenie listy:

    >>> cars = ["bmw", "audi", "mercedes", "toyota", "nissan"]
    

    Aby upewnić się, że mamy do czynienia z listą, możemy skorzystać z wbudowanej funkcji type:

    >>> cars = ["bmw", "audi", "mercedes", "toyota", "nissan"]
    >>> type(cars)
    <class 'list'>
    

    Do sprawdzenia długości listy, jak w przypadku każdej sekwencji w Pythonie, służy funkcja len:

    >>> len(cars)
    5
    

    Dostęp do elementów

    Do elementów listy odwołujemy się za pomocą ich indeksów. W Pythonie, tak jak w większości prawilnych języków programowania, elementy indeksowane są od zera. Czyli jeśli chcę otrzymać pierwszy element z listy, to wykonam:

    >>> cars[0]
    'bmw'
    

    W przypadku odwołąnia do nieistniejącego elementu, to otrzymam błąd:

    >>> cars[10]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    IndexError: list index out of range
    

    Jako że lista jest strukturą mutowalną, to możemy zmienić wartość listy pod danym indeksem:

    >>> cars[0] = "hyundai"
    >>> cars
    ['hyundai', 'audi', 'mercedes', 'toyota', 'nissan']
    

    To, o czym mówiliśmy do tej pory, jest dosyć typowe dla wielu języków programowania. Ale Python oferuje dużo więcej bardzo zgrabnych funkcjonalności dla list

    Możemy odczytywać  elementy listy od jej końca! W tym celu należyć użyć ujemnych indeksów. Czyli aby otrzymać ostatni element z listy, wystarczy napisać:

    >>> cars[-1]
    'nissan'
    

    Zauważmy, że wcześniej, aby otrzymać pierwszy element z listy, użyliśmy indeksu 0, natomiast teraz nie użyliśmy -0, ale -1. Trzeba pamiętać, że "patrząc od tyłu", elementy są „indeksowane od -1”.

    A co stałoby się po użyciu -0?

    >>> cars[-0]
    'hyundai'
    

    Otrzymamy po prostu pierwszy element listy. Czyli wywołania cars[0] i cars[-0] są całkowicie równoważne.

    Slicing (krajanie na plasterki?) listy w Pythonie

    Kolejną superopcją w Pythonie jest slicing, czyli możliwość łatwego wydzielania fragmentów z sekwencyjnych struktur danych takich jak lista.

    Jeśli chcemy na przykład ograniczyć naszą listę do dwóch pierwszych elementów, to napiszemy:

    
    >>> cars[:2]
    ['hyundai', 'audi']
    

    A jeśli chcemy wybrać co drugi element z listy?

    >>> cars[::2]
    ['bmw', 'mercedes', 'nissan']
    

    Co tu się właściwie dzieje?
    Pełna formuła slicingu wygląda start:stop:krok. Start to indeks elementu, od którego zaczynamy slicing a stop to indeks, przed którym zakończymy slicing. Natomiast krok określa co który element będziemy brać pod uwagę.

    Jak widać w powyższych przykładach możemy pomijać różne z tych opcji. Na przykład nie podając start zaczniemy domyślnie od pierwszego elementu, a nie podając stop skończymy na ostatnim. A domyślny krok wynosi 1, czyli bierze pod uwagę każdy element.

    Poniżej jeszcze kilka przykładów:

    >>> cars = ['bmw', 'audi', 'mercedes', 'toyota', 'nissan']
    >>> cars[1:]
    ['audi', 'mercedes', 'toyota', 'nissan']
    >>> cars[1:3]
    ['audi', 'mercedes']
    >>> cars[:3]
    ['bmw', 'audi', 'mercedes']
    >>> cars[1::2]
    ['audi', 'toyota']
    

    Bardzo ciekawym trikiem jest wykorzystanie kroku do odwócenia listy. Jak to zrobić? Wystarczy podać jako krok wartość -1:

    >>> cars[::-1]
    ['nissan', 'toyota', 'mercedes', 'audi', 'bmw']
    

    Taki to ten nasz Python fajny 😄

    Warto zauważyć, że przy slicingu nie modyfikujemy oryginalnej listy. Pozostaje ona bez zmian, a jako wynik operacji otrzymujemy nową listę:

    >>> reversed_cars = cars[::-1]
    >>> reversed_cars
    ['nissan', 'toyota', 'mercedes', 'audi', 'bmw']
    >>> cars
    ['bmw', 'audi', 'mercedes', 'toyota', 'nissan']
    

    Dodawanie elementów do listy

    Do dodawania nowego elementu na końcu listy służy metoda append():

    >>> cars.append("ferrari")
    >>> cars
    ['bmw', 'audi', 'mercedes', 'ferrari']
    

    Jeśli chcemy natomiast dodać wiele elementów na raz, to możemy skorzystać z metody extend() – jako argument podajemy dowolny iterable, np. listę lub tuplę:

    >>> cars
    ['bmw', 'audi', 'mercedes']
    
    >>> cars.extend(["honda", "rover"])
    >>> cars
    ['bmw', 'audi', 'mercedes', 'honda', 'rover']
    

    To samo możemy osiągnąć również dodając do siebie dwie listy przy pomocy „plusa” (+). Przy czym w tym wypadku oryginalna lista nie jest modyfikowana – otrzymujemy nową listę:

    >>> more_cars = cars + ["honda", "rover"]
    >>> more_cars
    ['bmw', 'audi', 'mercedes', 'honda', 'rover']
    >>> cars
    ['bmw', 'audi', 'mercedes']
    

    A co jeśli chcemy dodać element w dowolnym miejscu, a nie tylko na końcu? Do tego służy metoda insert(index, elem). Argument index określa, przed jakim elementem wstawimy nowy:

    >>> cars.insert(0, "honda") # na początku listy
    >>> cars
    ['honda', 'bmw', 'audi', 'mercedes']
    
    >>> cars.insert(3, "rover") # przed elementem o indeksie 3
    >>> cars
    ['honda', 'bmw', 'audi', 'rover', 'mercedes']
    
    >>> cars.insert(len(cars), "ferrari") # na końcu listy, równoważne z append()
    >>> cars
    ['honda', 'bmw', 'audi', 'rover', 'mercedes', 'ferrari']
    

    Usuwanie elementów z listy

    Ok, a co zrobić jak masz już za dużo tych samochodów? 😎
    Jeśli chcesz po prostu usunąć go z listy, to użyj metody remove(). Jako argument podajemy wartość elementu, który chcemy usunąć.

    Usunięty zostanie pierwszy element o tej wartości. A jeśli nie ma żadnego, to Python zwróci ValueError.

    >>> cars
    ['honda', 'bmw', 'audi', 'rover', 'mercedes', 'ferrari']
    
    >>> cars.remove("mercedes")
    >>> cars
    ['honda', 'bmw', 'audi', 'rover', 'ferrari']
    >>> cars.remove("maserati")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: list.remove(x): x not in list
    

    No dobra, a jak usunąć dowolny element? Jest taka bardzo fajna metoda jak pop(index), która oprócz usunięcia elementu jeszcze nam go zwraca!
    Możemy podać wartość index, spod którego chcemy otrzymać element. Jeśli go nie podamy to dostaniemy ostatni:

    >>> cars
    ['honda', 'bmw', 'audi', 'rover', 'ferrari']
    
    >>> item = cars.pop()
    >>> item
    'ferrari'
    >>> cars
    ['honda', 'bmw', 'audi', 'rover']
    
    >>> another_item = cars.pop(1)
    >>> another_item
    'bmw'
    >>> cars
    ['honda', 'audi', 'rover']
    

    Pozostao nam jeszcze zerowanie listy. Możemy to zrobić na dwa sposoby:

    >>> cars.clear()
    >>> cars
    []
    
    >>> del cars[:]
    >>> cars
    []
    

    Wyszukiwanie elementów

    Zobaczmy jeszcze jak możemy znaleźć położenie elementu w liście szukając po jego wartości. Użyjemy do tego metody index().
    Dla odpoczynku od aut pobawmy się teraz owocami 🍌

    >>> fruits = ["banana", "raspberry", "apple", "banana"]
    >>> fruits.index("banana")
    0
    

    Zauważ, że otrzymaliśmy index pierwszego z kolei elementu o podanej wartości. Ale możemy użyć dodatkowych elementów metody index(), żeby zawęzić przedział wyszukiwania:

    >>> fruits.index("banana", 1, 4)
    3
    

    Przy czym sytuacja wygląda znowu tak jak przy slicingu – początek przedziału jest „zamknięty” (czyli szukamy od indeksu 1), a koniec jest „otwarty” (szukamy tak naprawdę do indeksu 3, a nie 4).

    Jeśli elementu w ogóle nie ma na liście, to dostaniemy ValueError. Żeby tego uniknąć, możemy najpierw sprawdzić, czy dana wartość w ogóle występuje w liście, używając słówka kluczowego in:

    >>> fruits.index("peach")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: 'peach' is not in list
    
    >>> "peach" in fruits
    False
    

    I na koniec możemy jeszcze zliczyć ilość wystąpień danej wartości w liście:

    >>> fruits.count("banana")
    2
    

    Sortowanie i odwracanie listy

    Jedną z takich operacji jest sortowanie listy. Jak możecie się już pewnie domyślić, służy do tego metoda sort():

    >>> fruits
    ['banana', 'raspberry', 'apple', 'banana']
    
    >>> fruits.sort()
    >>> fruits
    ['apple', 'banana', 'banana', 'raspberry']
    

    Sortowanie dokonuje się in place, czyli zmieniamy naszą listę, a nie tworzymy nowej. Wartości porównywane są do siebie w zależności od typu: stringi alfabetycznie, liczby w kolejności etc.

    >>> nums = [4, 3, 7, 9, 1]
    >>> nums.sort()
    >>> nums
    [1, 3, 4, 7, 9]
    

    Ale jak zapewne pamiętamy, w liście możemy przechowywać dane różnego typu! Na przykład stringi i liczby jednocześnie. Wówczas lista nie zostanie posortowana. Do tego zwróci wyjątek:

    >>> mixed = ["kangaroo", 5, "elephant", 2]
    >>> mixed.sort()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: '<' not supported between instances of 'int' and 'str'
    

    No niestety, sortowanie nie jest dla wszystkich.
    Ale jeśli chcemy zmodyfikować trochę logikę sortowania, to możemy podać jako argument key funkcję, która zwróci wartość, po której będziemy sortować.

    Żeby to pokazać wróćmy do naszych owoców. Załóżmy, że nie chcemy tej listy sortować alfabetycznie, tylko po długości słów – od najkrótszego do najdłuższego:

    >>> fruits = ["apple", "raspberry", "mango", "banana", "pineapple"]
    >>> fruits.sort(key=len)
    >>> fruits
    ['apple', 'mango', 'banana', 'raspberry', 'pineapple']
    

    Jako key podaliśmy tutaj wbudowaną funkcję len(x), ale może to być dowolna funkcja przyjmująca jeden argument – będzie to każdy element naszej listy po kolei.

    Odwrócenie kolejności sortowania jest bardzo proste:

    >>> fruits.sort(key=len, reverse=True)
    >>> fruits
    ['raspberry', 'pineapple', 'banana', 'apple', 'mango']
    

    No właśnie, a co jeśli chcemy odwrócić naszą listę tak po prostu, bez sortowania? Może pamiętasz, że przy slicingu pokazywałem taki sposób:

    >>> fruits = ["apple", "raspberry", "mango", "banana", "pineapple"]
    >>> fruits[::-1]
    ['pineapple', 'banana', 'mango', 'raspberry', 'apple']
    

    W ten sposób otrzymujemy nową, odwróconą listę, a stara zostaje bez zmian. Ale jest jeszcze jeden sposób odwracania, gdzie znów robimy to in place, modyfikując oryginalną kolekcję:

    >>> fruits
    ['apple', 'raspberry', 'mango', 'banana', 'pineapple']
    >>> fruits.reverse()
    >>> fruits
    ['pineapple', 'banana', 'mango', 'raspberry', 'apple']
    

    Kopiowanie listy

    Służy do tego – a jakże – metoda copy()!

    >>> new_fruits = fruits.copy()
    >>> new_fruits
    ['apple', 'raspberry', 'mango', 'banana', 'pineapple']
    

    Musisz jednak wiedzieć, że jest to tak zwana płytka kopia (ang. shallow copy). W podanym przykładzie nie ma to znaczenia, bo przechowujemy w naszej liście prosty typ zmiennej – string, który jest niemutowalny.

    Ale gdybyśmy naszej liście trzymali bardziej złożone obiekty (np. słownik – dict), to po dokonaniu takiej płytkiej kopii, zmieniając „zawartość” naszych złożonych obiektów wpływamy na zawartość obu list:

    >>> complex = [
    ... {"name": "John", "age": 27},
    ... {"name": "Martha", "age": 24}
    ... ]
    
    >>> new_complex = complex.copy()
    >>> complex
    [{'name': 'John', 'age': 27}, {'name': 'Martha', 'age': 24}]
    >>> new_complex
    [{'name': 'John', 'age': 27}, {'name': 'Martha', 'age': 24}]
    
    >>> complex[0]['name'] = "Luke"
    >>> complex
    [{'name': 'Luke', 'age': 27}, {'name': 'Martha', 'age': 24}]
    >>> new_complex
    [{'name': 'Luke', 'age': 27}, {'name': 'Martha', 'age': 24}]
    

    Zauważ, że zmiana wartości w słowniku poprzez odniesienie do oryginalnej listy wpłynęła też na wartość w drugiej liście.

    Ma to związek z tym, o czym pisałem na samym początku artykułu – lista tak naprawdę nie przechowuje samych wartości swoich elementów, a jedynie referencje do nich.

    Dlatego w przypadku takiej płytkiej kopii obie listy de facto wskazują na te same obiekty w pamięci 😉



    Zadania
    Utwórz plik wykonywalny ...

    1. Utwórz listę 100 losowych liczb z zakresu <1-1000> następnie wykonaj poniższe ćwiczenia:
      1. Napisz program, który obliczy i wypisze na ekran sumę wszystkich elementów listy.
      2. Napisz program, który znajdzie i wypisze na ekran najmniejszy element listy (wykonaj 2 wersje, bez użycia i używając wbudowaną funkcję języka Python).
      3. Napisz program, który znajdzie i wypisze na ekran największy element listy (wykonaj 2 wersje, bez użycia i używając wbudowaną funkcję języka Python).
      4. Napisz program, który znajdzie i wypisze na ekran medianę elementów listy.
      5. Napisz program, który posortuje elementy listy od najmniejszego i wypisze na ekran pierwsze 20 z nich (wykonaj 2 wersje, bez użycia i używając wbudowaną funkcję języka Python).
      6. Napisz program, który obliczy i wypisze na ekran iloczyn wszystkich elementów listy.
      7. Napisz program, który sprawdzi i wypisze na ekran ilość liczb 3-cyfrowych na liście
      8. Napisz program, który sprawdzi i wypisze na ekran liczbę oraz jej ilość powtórzeń, która najczęściej występuje na liście.
      9. Napisz program, który sprawdzi i wypisze na ekran wszystkie liczby, które się nie powtarzają na liście.
      10. Napisz program, który sprawdzi i wypisze na ekran, które liczby powtarzają się na liście dokładnie 3 razy.
      11. Napisz program, który sprawdzi i wypisze na ekran, które liczby zawierają w sobie liczbę 21, np. 21, 213, 521.
      12. Napisz program, który sprawdzi i wypisze na ekran ile liczb jest większych niż 800.
      13. Napisz program, który sprawdzi i wypisze na ekran trzy najmniejsze i trzy największe liczby z listy.
      14. Napisz program, który usunie z listy duplikaty, następnie wypisze na ekran ilość pozostałych elementów.
      15. Napisz program, który pomiesza zawartość listy. Wypisz zawartość listy przed i po pomieszaniu jej elementów.
      16. Napisz program, który przekonwertuje wszystkie elementy tablicy z int na string.
      17. Wypisz wszystkie elementy listy, umieszczając przy każdym informację, ile razy występuje na liście.
      18. Oblicz ile jest elementów listy, których wartość mieści się w przedziale <a,b>. Wartości a i b podaje użytkownik.
      19. Oblicz ile jest elementów listy, których wartość jest parzysta.
      20. Oblicz ile jest elementów listy, których wartość jest nieparzysta.
      21. Napisz program, który przeniesie wszystkie elementy parzyste listy posegregowane od najmniejszego na lewą stronę listy, natomiast nieparzyste posegregowane malejąco na prawą. Np. [2,1,4,6,3,6,5] -> [2,4,6,6,5,3,1] 

         

    2. Napisz program, który utworzy n-elementową listę składającą się z <1-x> znakowych ciągów. Wartości n oraz x podaje użytkownik. Np. n = 3, x = 5, przykładowa lista: [‘thbdr’,’pw’,’oerv’], następnie wykonaj na niej następujące ćwiczenia:
      1. Napisz program, który sprawdzi i wypisze na ekran ilość znaków w liście.
      2. Napisz program, który sprawdzi i wypisze na ekran ile liter ‘k’ zawiera lista.
      3. Napisz program, który sprawdzi i wypisze na ekran ile ciągów znaków: ‘kt’ zawiera lista
      4. Napisz program, który sprawdzi i wypisze na ekran ile ciągów znaków dłuższych niż s zawiera lista. Wartość s podaje użytkownik.
      5. Napisz program, który na początku każdego elementu listy doda literę a, a na końcu literę z. Np. [‘csae’, ‘eg’, ‘rr’] -> [‘acsaez’, ‘aegz’, ‘arrz’] 
    3. Napisz program, który utworzy dwuwymiarową listę 4×6, gdzie każdy element będzie posiadał zawartość: *
    4. Napisz program, który utworzy dwuwymiarową listę 4x6x3, gdzie każdy element będzie posiadał zawartość: *
    5. Napisz program, który utworzy listę elementów będących kwadratami liczb z przedziału <2,20>
    6. Napisz program, który utworzy następującą listę: [1,2,3,4,5], następnie wypisze na ekran jej wszsytkie kombinacje elementów, jednak w innym ułożeniu (permutacje). Np. [1,2,3,5,4], [5,4,3,2,1], [4,3,5,1,2], itd.
    7. Utwórz 2 listy 10-elementowe, gdzie wartości elementów poda użytkownik. Utwórz 3 listę 10-elementową zawierającą różnicę elementów mających te same indeksy w 2 wypełnionych tabelach.
    8. Użytkownik podaje wartość x, będącą ciągiem znaków oraz wartość y będącą liczbą naturalną. Utwórz listę zawierającą następujący wzorzec połączenia obu zmiennych: np. x = ‘abc’, y = 3, lista=[‘a1′,’b1′,’c1′,’a2′,’b2′,’c2′,’a3′,’b3′,’c3’]
    9. Użytkownik podaje wartość trzech liczb całkowitych. Utwórz z nich listę. Następnie pobierze elementy listy i utwórz z nich jedną liczbę całkowitą i wypisz na ekran. Np. 23, 34, 45 -> [23, 34, 45] -> 233445
    10. Utwórz listę składającą się ze wszystkich liter alfabetu. Co n-ty element podziel listę na podlisty. Wartość n podaje użytkownik. Np. [‘a’,’b’,’c’,’d’,’e’,’f’,’g’,’h’] , n=3 -> [[‘a’,’b’,’c’],[‘d’,’e’,’f’],[‘g’,’h’]]