Python Vadovėlis/Daugiau apie sąrašus

Iš wiki.angis.net.
Jump to navigation Jump to search
 ← Modulių naudojimas Turinys Daugiau apie tekstines eilutes → 

Apie sąrašus ir jų panaudojimą jau girdėjai praėjusiame skyriuje. Dabar, kai turi daugiau žinių, aš išsamiau aprašysiu sąrašus. Iš pradžių parodysiu, kaip dirbti su sąrašo elementais ir tuomet papasakosiu, kaip juos galima kopijuoti.

Parašiau pavyzdį, kuriame naudoju indeksus, kad pasiimčiau vieną konkretų elementą iš sąrašo:

>>> skaičiai = ['nulis', 'vienas', 'du', 'trys', 'keturi', 'penki']
>>> skaičiai[0]
'nulis'
>>> skaičiai[4]
'keturi'
>>> skaičiai[5]
'penki'

Visi šie pavyzdžiai tau turėtų atrodyti pažįstami. Jei nori gauti pirmąjį sąrašo elementą, tu žiūri į indeksą 0, jei nori antrojo, tuomet imi indeksą 1 ir taip toliau judi per visą sąrašą. Tačiau ką daryti, jei nori paskutinio sąrašo elemento? Vienas iš būdų galėtų būti funkcijos len() panaudojimas: skaičiai[len(skaičiai) - 1]. Funkcija len() visada grąžina elementų kiekį + 1. Šiuo būdu gali eiti per sąrašą iš kitos pusės, pavyzdžiui: antrasis sąrašo elementas nuo galo yra gaunamas taip: skaičiai[len(skaičiai) - 2]. Kaip jau minėjau, yra dar vienas būdas, kaip galėtum pasiekti tą patį rezultatą. Python'e paskutinis elementas sąraše visada turi indeksą -1, antrojo elemento nuo sąrašo pabaigos indeksas yra -2 ir taip toliau. Štai daugiau pavyzdžių:

>>> skaičiai[len(skaičiai) - 1]
'penki'
>>> skaičiai[len(skaičiai) - 2]
'keturi'
>>> skaičiai[-1]
'penki'
>>> skaičiai[-2]
'keturi'
>>> skaičiai[-6]
'nulis'

Taigi, bet kuris sąrašo elementas gali būti indeksuojamas dviem būdais: iš priekio ir iš galo.

Kitas naudingas būdas, kaip gali padalinti sąrašą ir gauti konkrečią jo dalį – pjaustymas (slicing). Štai pavyzdys, leidžiantis suprasti, kaip jis gali būti naudojamas:

>>> dalykai = [0, 'Jonas', 2, 'S.P.A.M.', 'Kojinė', 42, "Benas", "Liepa"]
>>> dalykai[0]
0
>>> dalykai[7]
'Liepa'
>>> dalykai[0:8]
[0, 'Jonas', 2, 'S.P.A.M.', 'Kojinė', 42, 'Benas', 'Liepa']
>>> dalykai[2:4]
[2, 'S.P.A.M.']
>>> dalykai[4:7]
['Kojinė', 42, 'Benas']
>>> dalykai[1:5]
['Jonas', 2, 'S.P.A.M.', 'Kojinė']

Pjaustymą naudoju tada, kai noriu gauti konkrečią sąrašo dalį. Pjaustymo operatorius yra aprašomas taip: dalykai[pirmas_indeksas:paskutinis_indeksas]. Pjaustymas „perpjauna“ sąrašą ties pirmas_indeksas ir paskutinis_indeksas ir tuomet grąžina tą sarašo dalį, kuri yra tarp pirmo indekso ir paskutinio indekso. Gali naudoti abiejų tipų indeksavimą:

>>> dalykai[-4:-2]
['Kojinė', 42]
>>> dalykai[-4]
'Kojinė'
>>> dalykai[-4:6]
['Kojinė', 42]

Dar vienas dalykas, kurį turėtum žinoti apie sąrašo pjaustymą - neapibrėžtas indeksas. Jei pirmas_indeksas nenurodytas, tuomet numatytoji reikšmė yra pirmojo elemento sąraše indeksas. Jei paskutinis paskutinis_indeksas nenurodytas, tuomet numatytoji reikšmė yra paskutiniojo elemento sąraše indeksas. Štai keli pavyzdžiai:

>>> dalykai[:2]
[0, 'Jonas']
>>> dalykai[-2:]
['Benas', 'Liepa']
>>> dalykai[:3]
[0, 'Jonas', 2]
>>> dalykai[:-5]
[0, 'Jonas', 2]

Štai programos pavyzdys (jei nori, nukopijuok ir išbandyk šios programos kodą):

poema = ["<B>", "Ta", "liga", "nelimpa", "</B>", "net", "ir", "prie",
        "savų.", "Pats", "<B>", "žiopliukas", "būdamas,", "neapkrės", "kitų.", "</B>",
        "Žiopliškumas", "buvo", "ir", "<B>", "visad", "jis", "bus.",
        "</B>", "Jei", "skandinsi", "pelkėj,", "<B>", "jis", "ir",
        "</B>", "ten", "nežus."]

def gauk_pastorintą(tekstas):
    true = 1
    false = 0
    ## ar_pastorintas pasako ar mes dabar tikriname 
    ## pastorintą teksto dalį.
    ar_pastorintas = false
    ## pradinis_blokas yra indeksas arba nepastorinta 
    ## teksto dalis arba pastorinta.
    pradinis_blokas = 0
    for indeksas in range(len(tekstas)):
        ## Apdorojama pastorinto teksto pradžia 
        if tekstas[indeksas] == "<B>":
            if ar_pastorintas:
                print("Klaida: Papildoma pastorinimo atidarymo žyma")
            ## print "Nepastorintas:", tekstas[pradinis_blokas:indeksas]
            ar_pastorintas = true
            pradinis_blokas = indeksas + 1
        ## Apdorojama pastorinto teksto pabaiga
        ## Atsimink, kad paskutinis skaičius atliekant pjūvį yra indeksas 
        ## po to, kai paskutinis indeksas yra panaudotas.
        if tekstas[indeksas] == "</B>":
            if not ar_pastorintas:
                print("Klaida: papildoma pastorinimo uždarymo žyma")
            print("Pastorintas [", pradinis_blokas, ":", indeksas, "]", tekstas[pradinis_blokas:indeksas])
            ar_pastorintas = false
            pradinis_blokas = indeksas + 1

gauk_pastorintą(poema)

šios programos išvestis yra:

Pastorinta [ 1 : 4 ] ['Ta', 'liga', 'nelimpa']
Pastorinta [ 11 : 15 ] ['žiopliukas', 'būdamas,', 'neapkrės', 'kitų.']
Pastorinta [ 20 : 23 ] ['visad', 'jis', 'bus.']
Pastorinta [ 28 : 30 ] ['jis', 'ir']

Funkcija gauk_pastorintą() pasiima sau į sąrašą tai, kas buvo padalinta į žodžius ir žymas. Žymos, kurį ši funkcija ieško - <B>, nes ji pradeda pastorintą tekstą ir </B>, kuris užbaigia pastorintą tekstą. Funkcija gauk_pastorintą() eina per tekstą ir ieško pradžios ir pabaigos žymų.

Kitas dalykas, kurį gali daryti su sąrašais - juos kopijuoti, pavyzdžiui:

>>> a = [1, 2, 3]
>>> b = a
>>> print(b)
[1, 2, 3]
>>> b[1] = 10
>>> print(b)
[1, 10, 3]
>>> print(a)
[1, 10, 3]

Šis pavyzdys turėtų nustebinti, kadangi pakeitus b pasikeitė ir a. Taip yra todėl, kad teiginys b = a sukūrė nuorodą (reference)b į a, o tai reiškia, jog b dabar yra dar vienas a vardas. Taigi, bet koks b pakeitimas, keičia ir a. Tačiau kai kurie priskyrimai nesukuria dviejų pavadinimų vienam sąrašui, pažvelk į dar vieną pavyzdį:

>>> a = [1, 2, 3]
>>> b = a * 2
>>> print(a)
[1, 2, 3]
>>> print(b)
[1, 2, 3, 1, 2, 3]
>>> a[1] = 10
>>> print(a)
[1, 10, 3]
>>> print(b)
[1, 2, 3, 1, 2, 3]

Šiuo atveju b nėra nuoroda į a, nes išraiška a * 2 sukuria naują sąrašą vietoje nuorodos į a. Beveik visos priskyrimo operacijos sukuria nuorodą, pavyzdžiui: kai perduodi sąrašą, kaip funkcijos argumentą, tu sukuri nuorodą. Visgi, dažniau mums programoje reikia kopijų, o ne nuorodų. Kai norime pakeisti vieną sąrašą, nekeisdami kito sąrašo, mes turime įsitikinti, kad sukūrėme sąrašo kopiją.

Yra keli būdai, kaip gali sukurti sąrašo kopiją. Vienas iš paprasčiausių būdų yra pjaustymo operatorius, kadangi jis visuomet sukuria naują sąrašą, net tada, kai su pjūviu apimame viso sąrašo ilgį:

>>> a = [1, 2, 3]
>>> b = a[:]
>>> b[1] = 10
>>> print(a)
[1, 2, 3]
>>> print(b)
[1, 10, 3]

Panaudoję pjūvio operatorių [:] mes sukuriame naują sąrašo kopiją. Turėk omeny, kad nukopijuojamas yra tik išorinis sąrašas. Bet koks vidinis sąrašas turi nuorodą į pirminį sąrašą. Todėl, kai sąraše yra sąrašų, reikia nukopijuoti ir vidinius sąrašus. Tu tai gali padaryti pats, tačiau Python'as savyje jau turi modulį, kuris tai padaro už tave. Gali panaudoti funkciją deepcopycopy modulio:

>>> import copy
>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = a[:]
>>> c = copy.deepcopy(a)
>>> b[0][1] = 10
>>> c[1][1] = 12
>>> print(a)
[[1, 10, 3], [4, 5, 6]]
>>> print(b)
[[1, 10, 3], [4, 5, 6]]
>>> print(c)
[[1, 2, 3], [4, 12, 6]]

Iš pradžių atkreipk dėmesį į tai, kad a sąrašų sąrašas. Toliau, kai kodo eilutė b[0][1] = 10 yra vykdoma, tuomet a ir b pasikeičia, bet c ne. Taip nutiko todėl, kad vidiniai masyvai vis dar yra nuorodos, kai naudojamas pjūvio operatorius. Iš kitos pusės, deepcopy c buvo visiškai nukopijuotas.

Taigi, ar turėčiau nerimauti dėl nuorodų kiekvieną kartą, kai naudoju funkciją ar =? Geros naujienos yra tos, kad tau reikia nerimauti apie nuorodas tik naudojant žodynus ir sąrašus. Priskiriant skaičiaus ar teksto eilutės reikšmes turinčius kintamuosius nuorodos nesukuriamos ir tau nereikia sukti galvos ar netikėtai pasikeis reikšmė. Tačiau tau reikia turėt omeny nuorodas, kai keiti sąrašus ir žodynus.

Turbūt susimąstei, kam išvis yra reikalingos nuorodos? Pagrindinė priežastis – greitis. Sukurti nuorodą sąrašo tūkstančiui elementų yra daug greičiau nei sukurti jų kopijas. Dar viena priežastis – tai, kad tu gali turėti funkciją, kuri leidžia modifikuoti sąrašus arba žodynus. Jei kada nors susidursi su keistomis problemomis, kai duomenys pasikeičia, nors neturėtų, tai prisimink apie nuorodas.


 ← Modulių naudojimas Turinys Daugiau apie tekstines eilutes →