Ostali bomo pri tvitih, s katerimi smo se igrali že prejšnji teden. Pri reševanju naloge je dovoljeno uporabljati vse funkcije, ki ste jih napisali prejšnji teden. Lahko jih preprosto skopirate na začetek tega programa - ne glede na to, katere boste potrebovali in katerih ne. Še več, namesto svojih lahko skopirate funkcije iz objavljene rešitve -- če delujejo boljše ali pa če sami naloge prejšnji teden niste reševali.

Testi

testi-spet-tviti.py

Obvezne naloge

  1. Funkcija besedilo(tvit) prejme tvit in vrne besedilo - torej vse, kar sledi prvemu dvopičju. Klic besedilo("ana: kdo so te: @berta, @cilka, @dani?") vrne "kdo so te: @berta, @cilka, @dani?.

    Ko smo iskali avtorja, smo niz razdelili glede na dvopičje in vrnili vse, kar je pred njim.

    def avtor(tvit):
        return tvit.split(":")[0]
    

    Če je kdo mislil, da bo dobil besedilo na enak način in je poskusil

    def avtor(tvit):
        return tvit.split(":")[1]
    

    sem ga prijazno zafrknil s tvitom "ana: kdo so te: @berta, @cilka, @dani? #krneki", ki vsebuje dve dvopičji.

    Pokličemo lahko index(':'), ki pove, kje je prvo dvopičje. Preskočimo le-tega in še presledek, ki mu sledi, ter vrnemo ves preostanek niza.

    def besedilo(tvit):
        return tvit[tvit.index(":") + 2:]
    

    Ali pa opazimo, da ima metoda split še en argument: povemo ji lahko, kolikokrat naj razdeli niz. Delimo glede na ": " - poleg dvopičja se tako znebimo še presledka. Dodatni argument, 1, pa pomeni, naj niz razdeli le enkrat, nadaljnje pojavitve ": " pa ignorira.

    def besedilo(tvit):
        return tvit.split(": ", 1)[1]
    
  2. Funkcija zadnji_tvit(tviti) prejme seznam tvitov in vrne slovar, katerega ključi so avtorji tvitov, vrednosti pa njihovi tviti. Če je en in isti avtor napisal več tvitov, naj bo v slovarju njegov zadnji tvit. Rezultat je lahko, recimo

    {"berta": "@sandra Delaj domačo za #programiranje1",
     "sandra": "@berta Ne maram #programiranje1 #krneki",
     "ana": "kdo so te: @berta, @cilka, @dani? #krneki"}
    

    če so to edini trije avtorji in so to njihovi (zadnji) tviti.

    Sestavimo prazen slovar, gremo čez vse tvite in za vsak tvit pod ključ avtor(tvit) dodamo besedilo(tvit). Če je isti avtor napisal več tvitov, kasnejši tviti povozijo prejšnje, kar je natančno to, kar hočemo.

    def zadnji_tvit(tviti):
        zadnji = {}
        for tvit in tviti:
            zadnji[avtor(tvit)] = besedilo(tvit)
        return zadnji
    

    Današnje predavanje bo postreglo s krajšo funkcijo. Sestaviti moramo slovar, katerega ključi so avtorji, vrednosti pa besedila, torej:

    def zadnji_tvit(tviti):
        return {avtor(tvit): besedilo(tvit) for tvit in tviti}
    
  3. Funkcija prvi_tvit(tviti) je jako podobna, le da v primeru, da je ista oseba napisala več tvitov, obdrži njen prvi tvit.

    Rešitev je taka kot prej, le da ne smemo povoziti tvitov, ki so že v slovarju.

    def prvi_tvit(tviti):
        prvi = {}
        for tvit in tviti:
            pisec = avtor(tvit)
            if pisec not in prvi:
                prvi[pisec] = besedilo(tvit)
        return prvi
    
  4. Funkcija prestej_tvite(tviti) vrne slovar, katerega ključi so (spet) avtorji, pripadajoče vrednosti pa število tvitov, ki so jih napisali, na primer {"sandra": 2, "berta": 1, "ana": 1, "cilka": 4, "benjamin": 1}

    Na predavanjih smo veliko šteli, torej bi moralo biti tole rutinsko.

    def prestej_tvite(tviti):
        stevci = defaultdict(int)
        for tvit in tviti:
            stevci[avtor(tvit)] += 1
        return stevci
    
  5. Funkcija omembe(tviti) vrne slovar, katerega ključi so avtorji tvitov, vrednosti pa seznami oseb, ki so jih ti avtorji omenjali v svojih tvitih. Vrstni red oseb mora biti enak vrstnemu redu omenjanj. Funkcija lahko vrne, recimo

    {"sandra": ["berta", "benjamin", "ana"],
    "benjamin": [],
    "cilka": [],
    "berta": ["sandra"],
    "ana": ["berta", "cilka", "dani"]}
    

    To je podobno štetju, le da ne prištevamo tvitov temveč dodajamo omembe.

    def omembe(tviti):
        afne = defaultdict(list)
        for tvit in tviti:
            afne[avtor(tvit)] += se_zacne_z(tvit, "@")
        return afne
    
  6. Funkcija neomembe(ime, omembe) prejme ime neke osebe in takšen slovar, kakršnega vrne gornja funkcija. Vrniti mora seznam vseh ljudi, ki so avtorji kakega tvita, podana oseba (ime) pa jih ni omenjala. Če funkciji kot argument podamo ime "Ana" in gornji slovar, mora vrniti ["sandra", "benjamin], saj Ana ni omenjala Sandre in Benjamina, Cilko in Berto pa je. Iz seznama naj bo seveda izključena oseba sama (v tem primeru Ana). Vrstni red oseb v seznamu je lahko poljuben.

    Pri tej funkciji se moramo spomniti, da imamo vse, kar potrebujemo, že v slovarju - tako vse avtorje tvitov (to so ključi slovarja omembe), kot vse omenjene (to je vrednost omembe[ime]). Gremo torej čez vse avtorje in zabeležimo vse, ki niso omenjeni.

    # Tole še ne deluje pravilno
    def neomembe(ime1, omembe):
        neomenjeni = []
        omenjeni = omembe[ime1]
        for avtor in omembe:
            if avtor not in omenjeni:
                neomenjeni.append(avtor)
        return neomenjeni
    

    Funkcija med neomenjene doda tudi avtorja samega. To lahko popravimo tako da pogoj if avtor not in omenjeni spremenimo v if avtor not in omenjeni and avtor != ime1. Še elegantneje pa je, če se delamo, da je omenil samega sebe in ga preprosto dodamo med omenjene, pa je mir.

    def neomembe(ime1, omembe):
        neomenjeni = []
        omenjeni = omembe[ime1] + [ime1]
        for avtor in omembe:
            if avtor not in omenjeni:
                neomenjeni.append(avtor)
        return neomenjeni
    

    Danes pa se bomo naučili, ko gre to preprosteje:

    def neomembe(ime1, omembe):
        return list(set(omembe) - set(omembe[ime1]) - {ime1})
    

Dodatna naloga

  1. Napišite funkcijo se_poznata(ime1, ime2, omembe), ki je podobna kot v prejšnji domači nalogi, le da kot argument namesto tvitov dobi gornji slovar. Povedati mora, ali je prva oseba kdaj omenila drugo (ali obratno) ali ne. Funkcija vrne True ali False.

    Rešitev naloge bi bila

    def se_poznata(ime1, ime2, omembe):
        return ime1 in omembe[ime2] or ime2 in omembe[ime1]
    

    vendar se utegne zgoditi (in seveda se zgodi, saj je teste pisal nek hudobnež), da katera od oseb ni napisala nobenega tvita in je torej ni v slovarju. Zatečemo se k metodi get.

    def se_poznata(ime1, ime2, omembe):
        return ime1 in omembe.get(ime2, []) or ime2 in omembe.get(ime1, [])
    
  2. Napišite funkcijo hashtagi(tviti), ki prejme seznam tvitov in vrne slovar, katerega ključi so hashtagi (brez znaka #), pripadajoče vrednosti pa seznami avtorjev, ki so uporabili ta hashtagi. Tagi naj bodo urejeni po abecedi.

    Sestavimo slovar, katerega ključi bodo hashtagi. Vzeli bomo defaultdict(list), da bomo vanj preprosteje dodajali avtorje. Potem gremo prek tvitov, pokličemo avtor(tvit), da dobimo pisca in potem tega pisca dodajamo k ustreznim tagom.

    Na koncu pa je potrebno urediti pisce: gremo čez vse vrednosti(!) v slovarju in za vsako pokličemo sort. Nekomu, ki o tem ne razmišlja preveč, ni čudno, da to deluje. Nekoga, ki bi se malo poglobil, pa bi lahko začudilo. Če je med nami kak tak, naj počaka do prihodnjih predavanj, ko bomo govorili prav o teh rečeh.

    def hashtagi(tviti):
        tagi = defaultdict(list)
        for tvit in tviti:
            pisec = avtor(tvit)
            for tag in se_zacne_z(tvit, "#"):
                tagi[tag].append(pisec)
        for avtorji in tagi.values():
            avtorji.sort()
        return tagi
    
Zadnja sprememba: torek, 23. marec 2021, 20.21