Flerdimensjonale lister


Opprette 2D-lister og indeksering
# Opprett en 2D-liste med gitte verdier (statisk opprettelse)
a = [[2, 3, 4], [5, 6, 7]]
print(a)
print(a[0])     # Elment nr 0 i a er en vanlig 1D-liste    --> [2, 3, 4]
print(a[0][1])  # Subliste nr 0, element nr 1 i sublisten  -->  3
# Opprett en 2D-liste
my_table = [
    ['a', 'b', 'c', 'd', 'e'],
    ['f', 'g', 'h', 'i', 'j'],
    ['k', 'l', 'm', 'n', 'o'],
    ['p', 'q', 'r', 's', 't'],
]

# Indeksering med to indekser; første indeks -> rad, andre indeks -> kolonne
print(my_table[0][0]) # a
print(my_table[0][1]) # b
print(my_table[0][2]) # c
print()
print(my_table[1][0]) # f
print(my_table[2][0]) # k
print(my_table[3][0]) # p
print()
print(my_table[1][4]) # gjett selv før du sjekker
print(my_table[3][2]) # gjett selv før du sjekker
Opprette 2D-lister med dynamisk størrelse

Vær forsiktig når du oppretter 2D-lister med dynamisk størrelse. Det er lett å gjøre feil. Se eksempelet under. For å få en god forståelse for hvorfor det blir feil her, er det lurt å benytte «se steg» -knappen.

# MISLYKKET forsøk på å opprette 2D-liste med dynamisk størrelse
rows = 3
cols = 2

a = [[0] * cols] * rows # Oppretter en «grunn» (overfladisk) kopi
                        # Oppretter én unik rad, resten er aliaser

print("Dette VIRKER SOM det er ok.  I begynnelsen:")
print("   a =", a) # [[0, 0], [0, 0], [0, 0]]

a[0][0] = 42
print("MEN, hva skjer etter at vi muterer a[0][0]=42?")
print("   a =", a) # [[42, 0], [42, 0], [42, 0]]
# RIKTIG måte å opprette en 2D-liste med dynamisk størrelse
rows = 3
cols = 2

a = []
for _ in range(rows):
    a.append([0] * cols)

print("Dette ER ok.  I begynnelsen:")
print("   a =", a) # [[0, 0], [0, 0], [0, 0]]

a[0][0] = 42
print("Etter at vi muterer a[0][0]=42")
print("   a =", a) # [[42, 0], [0, 0], [0, 0]]
# Alternativ RIKTIG måte å opprette en 2D-liste med dynamisk størrelse
# Her benytter vi listeinklusjon (engelsk: list comprehension)
rows = 3
cols = 2

a = [[0] * cols for _ in range(rows)]

print("Dette ER ok.  I begynnelsen:")
print("   a =", a) # [[0, 0], [0, 0], [0, 0]]

a[0][0] = 42
print("Etter at vi muterer a[0][0]=42")
print("   a =", a) # [[42, 0], [0, 0], [0, 0]]
Dimensjonene til en 2D-liste

En 2D-liste er en liste av lister. Selv om det ikke er påkrevd fra Python sin side, er det vanlig at alle de «innerste» listene er like lange; da kaller vi listen for et rutenett. Hver av de innerste listene representerer én rad, mens den ytterste listen inneholder alle radene.

# a er 2D-liste som representerer et rutenett (alle rader er like lange)
a = [
    [2, 3, 5],
    [1, 4, 7],
]
print("a = ", a)

# La oss finne dimensjonene til rutenettet
rows = len(a)
cols = len(a[0])
print("rows =", rows) # 2
print("cols =", cols) # 3
Løkker over 2D-lister
# a er 2D-liste som representerer et rutenett (alle rader er like lange)
a = [
    [2, 3, 5],
    [1, 4, 7],
]
print("Først: a =", a)

# Vi finner dimensjonene til rutenettet
rows = len(a) # 2
cols = len(a[0]) # 3

# En løkke over hvert element i listen
# I eksempelet under øker vi verdien til hver celle i rutenettet med 1
for row in range(rows):
    for col in range(cols):
        # Koden her inne kjøres rows*cols ganger, én gang for hver
        # kombinasjon av verdier for row og col (altså én gang for hver «celle»)
        a[row][col] += 1

# Til slutt, utskrift av resultatet
print("Etter:  a =", a)
Hente ut rader og kolonner

Få tilgang til en hel rad.

# Et alias, ikke en kopi! Ingen ny liste opprettes!
a = [[2, 3, 5], [1, 4, 7]]
row = 1
row_list = a[row]
print(row_list)

Få tilgang til en hel kolonne.

# IKKE et alias, men en kopi! Ny liste opprettes!
a = [[2, 3, 5], [1, 4, 7]]
col = 1
col_list = [] 
for row in range(len(a)):
    col_list.append(a[row][col])
print(col_list)

Få tilgang til en hel kolonne med listeinklusjon.

# IKKE et alias, men en kopi! Ny liste opprettes!
a = [[2, 3, 5], [1, 4, 7]]
col = 1
col_list = [a[row][col] for row in range(len(a))]
print(col_list)
Grunne og dype kopier

Først, et mislykket forsøk på å kopiere en 2D-liste. Du vil (dessverre) få samme oppførsel uansett hvilken variant av kopiering fra kursnotatene om 1D-lister du bruker.

Problemet med å lage en kopi av flerdimensjonell liste, er at innholdet i lister egentlig er referanser til verdier, og ikke er verdier i seg selv. Så om du kopierer en referanse - da får vi et alias.

# MISLYKKET forsøk på å kopiere en 2D-liste
import copy
a = [[1, 2, 3], [4, 5, 6]]

b = copy.copy(a) # Fra kursnotatene om 1D-lister

print("Dette VIRKER SOM det er ok.  I begynnelsen:")
print("   a =", a)
print("   b =", b)

a[0][0] = 42
print("MEN, hva skjer etter at vi muterer a[0][0]=42?")
print("   a =", a)
print("   b =", b)
# RIKTIG måte å kopiere en 2D-liste
import copy
a = [[1, 2, 3], [4, 5, 6]]

b = copy.deepcopy(a)

print("Dette ER er ok.  I begynnelsen:")
print("   a =", a)
print("   b =", b)

a[0][0] = 42
print("Etter at vi muterer a[0][0]=42")
print("   a =", a)
print("   b =", b)
3D-lister

En 2D-liste er bare en liste av lister. Det er selvsagt mulig å ha en liste av 2D-lister. Dette blir da en 3D-liste. En liste med 3D-lister blir en 4D-liste, og så videre.

a = [
        [
            [1, 2],
            [3, 4],
        ],
        [
            [5, 6, 7],
            [8, 9],
        ],
        [
            [10],
        ],
    ]

for i in range(len(a)):
    for j in range(len(a[i])):
        for k in range(len(a[i][j])):
            print(f'a[{i}][{j}][{k}] = {a[i][j][k]}')