CITATI

CITATI

Avtor: Manja Benak

BESEDILO NALOGE

Recimo, da bi radi citirali razne strani iz neke knjige; to naredimo tako, da naštejemo številke teh strani v strogo naraščajočem vrstnem redu, na primer 2, 5, 6, 8, 11, 28, 29, 30, 31, 67. Če se v tem seznamu kdaj pojavita dve ali več zaporednih strani, ga lahko zapišemo krajše: obdržimo le prvo in zadnjo številko strani iz take skupine več zaporednih številk, med njiju pa zapišimo vezaj: 2, 5–6, 8, 11, 28–31, 67.

Napiši program, ki prebere več seznamov številk strani z vhodne datoteke (pri čemer bo vsaka številka v svoji vrstici), na izhodno datoteko pa izpiše te sezname v zgoraj določeni obliki (v eni vrstici, z vejicami, presledki in vezaji). Seznami števil na vhodni datoteki so med seboj ločeni z vrstico, v kateri je le niz "#NOV SEZNAM#". V vhodnem seznamu številke strani niso nujno v naraščajočem vrstnem redu, vse pa so cela števila, večja od 0. Predpostaviš lahko, da je v vhodnem seznamu vsaj ena številka in da se nobena številka v njem ne pojavi več kot enkrat.

IDEJA REŠITVE

Torej napisati moramo funkcijo, ki prebere vhodno datoteko, sestavi sezname v ustrezni obliki in le te zapiše na izhodno datoteko.

Nalogo lahko rešimo tako, da napišemo dve funkciji in sicer: citati (vhodna, izhodna) in vezaji (seznam). Prva nam s pomočjo druge funkcije vrne iskano rešitev problema.

Ideja rešitve je v tem, da najprej preberemo vhodno datoteko in ugotovimo ali je v vhodni datoteki le en seznam zaporednih števil ali jih je več. Seznami so v vhodni datoteki ločeni z vrstico v kateri je le niz "#NOV SEZNAM#". Zato moramo ločiti posamezne sezname in jih shraniti. Ko bodo seznami ločeni, jih moramo še urediti tako, da bodo elementi le teh urejeni po velikosti naraščajoče.

Najtežji del naloge je v tem, kje postaviti vezaje. To naredimo tam, kjer se v seznamu pojavita dve ali več zaporednih strani. Obdržimo prvo in zadnje število iz take skupine več zaporednih števil in med njiju zapišemo vezaj. Ta del naloge sem rešila s pomočjo funkcije vezaji, ki kot parameter prejme naraščajoče urejen seznam in vrne niz, ki ga kasneje zapišemo na izhodno datoteko. Ta niz je torej take oblike: "2, 5–6, 8, 11, 28–31, 67.". S funkcijo vezaji torej pretvorimo vse sezname iz vhodne datoteke v tako obliko nizov in jih s funkcijo citati zapišemo v izhodno datoteko, vsak seznam v svojo vrstico.

KODA FUNKCIJE VEZAJI (1. del)

 def vezaji(seznam):
    assert type(seznam) == list, "Parameter seznam mora biti tipa seznam."
    for el in seznam:
        assert type(el) == int and el > 0, "V seznamu morajo biti pozitivna cela števila."
        pass
    if len(seznam) == 0:
        return ""
    if len(seznam) > 1:
        for indeks in range(1, len (seznam)):
            assert seznam[indeks-1] < seznam[indeks], "Parameter seznam mora biti naraščajoče urejen seznam."
            pass
    nov = []
    # Če je v seznamu eno samo število, ga pretvorimo v niz in dodamo seznamu nov, ki bo imel samo en element. Funkcija vezaji
    # v tem primeru vrne kar ta 1-elementni seznam nov.
    if len(seznam) == 1:
        nov.append(str(seznam[0])) 

Funkcija vezaji dobi kot parameter naraščajoče urejen seznam . Če je seznam prazen, funkcija vrne prazen niz. Če vsebuje seznam natanko en element, le tega pretvorimo v niz in ga dodamo v prej definiran prazen seznam nov .

KODA FUNKCIJE VEZAJI (2. del)

    # V seznamu seznam je več kot en element.
    else:
        # Z for zanko definiramo i, s katerim gremo po vseh elementih seznama seznam.
        for i in range(len(seznam)):
            # Če smo na začetku seznama seznam in če drugi element seznama seznam ni za 1 večji od prvega elementa seznama
            #seznam, potem seznamu nov lahko dodamo niz z vrednostjo prvega elementa seznama seznam.
            if i == 0 and seznam[i] != seznam[i+1] - 1:
                nov.append(str(seznam[i]))
            # Če smo na koncu seznama seznam in če zadnji element seznama seznam ni za 1 večji od predzadnjega elementa
            # seznama seznam, potem seznamu nov lahko dodamo niz z vrednostjo zadnjega elementa seznama seznam.
            elif i == len(seznam) - 1 and seznam[i] != seznam[i-1] + 1:
                nov.append(str(seznam[i]))
            # Če nismo ne na začetku in ne na koncu seznama seznam in če trenutni element seznama seznam ni za 1 večji od
            # predhodnjega elementa seznama seznam in za 1 manjši od naslednjega elementa seznama seznam, potem seznamu nov
            #lahko dodamo niz z vrednostko trenutnega elementa seznama seznam.
            elif seznam[i] != seznam[i-1] + 1 and seznam[i] != seznam[i+1] - 1:
                nov.append(str(seznam[i]))
            # V tem primeru imamo vsaj dve zaporedni števili, med katerima mora biti vezaj.
            else:
                # Z for zanko definiramo j, kateri nam pomaga ugotoviti, če se v seznamu seznam pojavljata dve ali več
                #zaporednih števil.
                for j in range(len(seznam)+1):
                    # Gledamo podsezname seznama seznam dolžine, ki vsebujejo vsaj 2 elementa.
                    if j > i + 1:
                        # Preverimo, če je seznam nov še prazen.
                        if len(nov) == 0:
                            # Če je seznam nov še prazen in če so v seznamu seznam od i-tega do vključno (j-1)-ega elementa
                            # zaporedne števile, potem seznamu nov na konec dodamo seznam od i-tega do vključno (j-1)-ega
                            # elementa.
                            if seznam[i:j] == list(range(seznam[i], seznam[i] + (j - i))):
                                nov.append(seznam[i:j])
                        # Preverimo, če je zadnji element v seznamu nov niz.
                        elif type(nov[-1]) == str:
                            # Če je zadnji element v seznamu nov tipa niz, to pomeni, da je (i-1)-ti element seznama seznam
                            # za več kot 1 manjši od (i)-tega elementa seznama seznam. Nato preverimo še, če so v seznamu
                            # seznam od i-tega do vključno (j-1)-ega elementa zaporedne številke, potem seznamu nov na konec
                            # dodamo seznam od i-tega do vključno (j-1)-ega elementa.
                            if seznam[i:j] == list(range(seznam[i], seznam[i] + (j - i))):
                                nov.append(seznam[i:j])
                        # V tem primeru seznam nov ni prazen in njegov zadnji element je tudi tipa seznam.
                        else:
                            # Če so v seznamu seznam od i-tega do vključno (j-1)-ega elementa zaporedne številke in če je
                            # prvi element zadnjega elementa seznama nov enak i-temu elementu seznama seznam, potem seznamu
                            # nov najprej izbrišemo zadnjii element (sedaj imamo daljše zaporedje zaporednih števil) in mu
                            # nato na konec dodamo seznam od i-tega do vključno (j-1)-ega elementa.
                            if seznam[i:j] == list(range(seznam[i], seznam[i] + (j - i))) and nov[-1][0] == seznam[i]:
                                del nov[-1]
                                nov.append(seznam[i:j])
                            # Če so v seznamu seznam od i-tega do vključno (j-1)-ega elementa zaporedne številke in če i-ti
                            # element seznama seznam NI element zadnjega elementa v seznamu nov (imamo novo zaporedje
                            # zaporednih števil), potem seznamu nov na konec dodamo seznam od i-tega do vključno (j-1)-ega
                            # elementa.
                            if seznam[i:j] == list(range(seznam[i], seznam[i] + (j - i))) and seznam[i] not in nov[-1]:
                                nov.append(seznam[i:j]) 

V tem delu pa v seznamu poiščemo tiste elemente, ki ne sestavljajo zaporedja zaporednih števil (pretvorimo jih v nize in dodamo v seznam nov ) in števila, ki tvorijo zaporedje zaporednih števil (ta števila kar v obliki seznama dodamo v seznam nov ). Sedaj so v seznamu nov shranjeni nizi oz. seznami (v nizih so števila, ki ne potrebujejo vezajev, v seznamih pa števila med katera je potrebno postaviti vezaj).

KODA FUNKCIJE VEZAJI (3. del)

niz = ''
    # Sedaj pa gremo z zanko for še po elementih seznama nov.
    for element in nov:
        # Če je element seznam nov tipa niz, ga dodamo nizu niz in mu dodamo še niz ", ".
        if type(element) == str:
            niz = niz + element + ', '
        # Če je element seznama nov tipa seznam, nizu niz dodamo niz z vrednostjo prvega in zadnjega elementa seznama ločenima z
        # vezajem. Na koncu nizu niz dodamo še niz ", "
        else:
            niz = niz + str(element[0]) + '-' + str(element[-1]) + ', '
    # Na koncu mora niz imeti piko, zato odstranimo niz ", " in mu dodamo na konec niz ".".
    niz = niz.strip(', ')
    niz += '.'
    # Vrnemo iskani niz.
    return niz 

Definiramo nov prazen niz niz , ki ga bo funkcija vračala. Sedaj pa gremo z for zanko še po elementih seznama nov in jih v ustrezni obliki dodajamo na konec niza niz . Če je element seznama "nov seznam, vzamemo samo prvi in zadnji element tega seznama in vmes postavimo vezaj. Ko dodamo posamezen preoblikovan element seznama nov na konec niza "niz mu dodamo še vejico in presledek. Na koncu pa samo še nizu niz dodamo piko in ga vrnemo.

KODA FUNKCIJE CITATI

import os

def citati (vhodna, izhodna):
    assert type(vhodna) == str and type(izhodna) == str, "Parametra morata biti podana kot niza."
    assert os.path.isfile(vhodna), "Vhodna datoteka ne obstaja."
    # Definiramo datotečno spremenljivko beri.
    beri = open(vhodna, 'rt')
    # Ustvarimo novo prazno datoteko.
    piši = open(izhodna, 'wt')
    seznam = []
    # Ustvarimo seznam z imenom seznam, katerega elementi so vrstice iz vhodne datoteke brez belih znakov na začetku in
    # koncu.
    for vrstica in beri:
        seznam.append(vrstica.strip())
    assert seznam[0] != "#NOV SEZNAM#" and seznam[-1] != "#NOV SEZNAM#", "Prvi in zadnji element v vhodni datoteki morata" +\
           "biti števili."
    seznamček = []
    n = 0
    # Ker je v vhodni datoteki lahko več seznamov, ki so med seboj ločeni z nizom "#NOV SEZNAM#", le te shranimo v seznam
    # seznamček.
    for i in range(len(seznam)):
        # Če je i-ti element seznama seznam enak nizu "#NOV SEZNAM#", to pomeni, da seznamčku dodamo podseznam seznama
        # seznam od n-tega do vključno i-1 elementa.
        if seznam[i] == "#NOV SEZNAM#":
            seznamček.append(seznam[n:i])
            n = i + 1
        # Če smo prišli do konca seznama seznam, to pomeni, da seznamčku dodamo podseznam seznama seznam od n-tega do
        # vključno i-tega elementa.
        if i == len(seznam) - 1:
            seznamček.append(seznam[n:i+1])
    # Elementi seznamčka so seznami.
    stevila = []
    # Elementi seznama stevila so seznami, katerih elementi so cela števila.
    for element in seznamček:
        stevila.append([int(k) for k in element])
    # Podsezname v seznamu stevila uredimo po velikosti naraščajoče.
    for podseznam1 in stevila:
        podseznam1.sort()
    # Sedaj, ko so podseznami v seznamu stevila urejeni po velikosti, jih preoblikujemo v obliko z vezaji s pomočjo funkcije
    # vezaji in nize, ki nam jih vrne funkcija vezaji zapišemo na izhodno datoteko vsakega v svojo vrstico.
    for podseznam2 in stevila:
        niz = vezaji(podseznam2) + '\n'
        piši.write(niz)
    # Zapremo vhodno datoteko.
    beri.close()
    # Zapremo izhodno datoteko.
    piši.close()

Funkcija citati najprej prebere vsebino vhodne datoteke in jo shrani v seznam . V seznamček shranimo podsezname, ki so v seznamu ločeni z elementom "#NOV SEZNAM#". Nato elemente v podseznamih seznamčka pretvorimo v cela števila in te pretvorjene podsezname uredimo po velikosti naraščajoče. Sedaj samo še s pomočjo prej definirane funkcije vezaji pretvorimo te urejene sezname v nize in vsakega posebej zapišemo na izhodno datoteko.

TESTNI PRIMERI

Pri funkciji vezaji moramo preveriti naslednje:

  • kaj se zgodi, če ji kot parameter podamo niz, celo število ali decimalno število.
  • kaj se zgodi, če ji kot parameter podamo neurejen seznam.
  • kaj se zgodi, če ji kot parameter podamo prazen seznam.
  • če nam funkcija vrača predvidene nize.

Pri funkciji citati moramo preveriti naslednje:

  • kaj se zgodi, če ji kot vhodne parametre podamo sezname, cela ali decimalna števila.
  • kaj se zgodi, če ji kot parameter podamo ime datoteke, ki ne obstaja.
  • kaj se zgodi, če je vhodna datoteka podana v neustrezni obliki.

TESTIRANJE - FILM (WINK)

0%
0%