Naloga

Najprej "disclaimer": srečal sem že veliko "Mustaf" in "Ahmedov", zato vem, da so prijaznejši od poprečnega Janeza in Jožeta. Zgodba, ki namiguje na tistih nekaj njihovih soimenjakov, ki jim niso v čast, naj ostane, da bo predavanje lepše teklo.

Naloga temelji na prejšnji nalogi. Pri njenem reševanju smete uporabiti objavljene rešitve prejšnje naloge, vendar jih morate zapakirati tako, kot velevajo spodnja navodila.

Sestavi funkcijo preberiKontakte(), ki prebere datoteko contacts.xml in kot rezultat vrne slovar, katerega ključi so kode oseb (npr. "57485e3ae987c39d"), vrednosti pa imena pripadajočih oseb (npr. "Fadil"). Za priloženo datoteko contacts.xml mora funkcija vrniti naslednji slovar:

>>> preberiKontakte() {'3d29777ba6fd7fea': 'Omar', 'adcd13753365d5dc': 'Mustafa', '91fc7e3a9f52aeea': 'Abdulah ibn Husein', '28757c8a8602ef17': 'Abdul', '441d4bd0a7f1bb61': 'Osama', '46e4aec0da28358a': 'Jibril', '31a35f8233b341b7': 'Ahmed', '8498a217b6b7e6a9': 'Fadil', '5e41cd57ce4f3198': 'Omar', '415cfac9b06b9745': 'Husein'}

Predpostavite lahko (ni pa vam treba), da .picasa.ini ne vsebuje dodatnih informacij, torej se na vsako sliko nanašajo natančno tri vrstice.

Nato sestavi funkcijo izlusci(vrstica, kontakti), ki kot argument dobi vrstico iz datoteke .picasa.ini, ki vsebuje obraze, in slovar, kakršnega vrne preberiKontakte. Funkcija izlusci mora vrniti množico vseh ljudi, ki se nahajajo v vrstici. Tule je primer, kaj mora funkcija znati.

>>> kontakti = preberiKontakte() >>> izlusciOsebe("faces=rect64(9ae536feca218f46),441d4bd0a7f1bb61;rect64(3863a3bfede8e4ba),91fc7e3a9f52aeea", kontakti) set(['Osama', 'Abdulah ibn Husein'])

To, kar smo napisali doslej, zahteva le, da svojo ali objavljeno rešitev naloge prepišete v dve funkciji. Zdaj pa še, kar je novega: napišite program, ki z uporabo gornjih funkcij prebere vsebino datotek contacts.xml in .picasa.ini ter sestavi slovar množic, iz katerega je vidno, kdo so znanci posamezne osebe. Rezultat naj bo shranjen v spremenljivki znanci, ki mora za dani datoteki izgledati natanko tako, kot kaže spodnji izpis (dovoljeno je le, da je spremenjen vrstni red oseb). Kaj, točno, je spodnja spremenljivka, pa odkrijte sami.

>>> znanci {'Ahmed': set(['Osama', 'Fadil', 'Mustafa', 'Jibril']), 'Mustafa': set(['Osama', 'Ahmed', 'Fadil', 'Omar', 'Jibril']), 'Abdulah ibn Husein': set(['Osama', 'Husein']), 'Abdul': set(['Osama']), 'Husein': set(['Abdulah ibn Husein']), 'Osama': set(['Abdulah ibn Husein', 'Abdul', 'Ahmed', 'Mustafa']), 'Fadil': set(['Ahmed', 'Mustafa', 'Omar', 'Jibril']), 'Omar': set(['Fadil', 'Mustafa']), 'Jibril': set(['Ahmed', 'Fadil', 'Mustafa'])}

Pri reševanju nalog uporabljajte priloženi datoteki; arhiv vsebuje tudi eno sliko. Ostale slike sem, tako kot oni material pred pol leta, poslal na WikiLeaks.

Namig: pojdite prek vrstic .picasa.ini in ko naletite na vrstico z obrazi, pokličite izlusciObraze. Nato pojdite čez vse pare obrazov in jih dodajte v slovar znanci. Pozorno preberite tisti del zapiskov s teh predavanj, ki se nanašajo na zadnjo uro (torej, zadnjo uro predavanj, ne smrtno posteljo), namreč telovadbo s seznami študentov, ki izbirajo predmete. Vse, kar morate početi, se skriva tam.

Za zagnane: namesti si modula matplotlib in networkx ter z njima nariši graf poznanstev. Videti bo, recimo tako:


Za najbolj zagnane: vzemi Picaso, pripravi si podobne podatke in nariši graf tako, da ima namesto točk sličice obrazov, izrezanih iz slik (to je, iz ene od slik, ki se nanašajo na vsako posamezno osebo).

Rešitev

Funkcijo preberiKontakte() ukrademo, kot so dovoljevala navodila, iz rešitve prejšnje naloge.

Prav tako moremo in smemo iz rešitve prejšnje naloge ukrasti branje vrstice z obrazi, tiste, ki se začne s faces=. Spremenimo jo le toliko, da zdaj zlaga osebe v množico, ki jo na koncu vrne kot rezultat.

Zdaj pa še branje datoteke in zlaganje v slovar množic.

kontakti = preberiKontakte() znanci = {} for slikanci in open(".picasa.ini"): if not slikanci.startswith("faces="): continue osebe = izlusciOsebe(slikanci, kontakti) for oseba in osebe: if oseba not in znanci: znanci[oseba] = set() znanci[oseba].update(osebe) for oseba, znani in znanci.items(): znani.remove(oseba)>

Najprej s preberiKontakte() sestavimo slovar oseb. Nato sestavimo prazen slovar, v katerega bomo zapisovali poznanstva. V zanki for nas zanimajo le vrstice, ki se začno s faces=; ostale preskočimo. Ker naloga obljublja, da bodo datoteke .picasa.ini "preproste" in bo faces= v vsaki tretji vrstici, začenši s prvo, bi smeli vrstice 3-5 zamenjati kar s

for slikanci in open(".picasa.ini").readlines()[1::3]: Ko vemo, da imamo vrstico z obrazi, iz nje izluščimo imena oseb, tako da pokličemo izlusciOsebe; osebe na sliki shranimo v osebe. Nato za vsako osebo iz množice osebe storimo tole. pogledamo, ali jo že imamo v slovarju znanci. Če je ni, jo dodamo in kot množico njenih znancev shranimo prazno množico. Nato v množico dosedanjih znancev te osebe (ki morda že vsebuje koga, morda pa smo jo pravkar naredili) dodamo vse osebe s te slike.

V zadnji zanki le še malo pospravljamo: iz množice znancev vsake osebe pobrišemo njo samo. Temu bi se dalo izogniti tako, da je niti ne bi dodali v množico (kar sem, priznam, nekaterim celo svetoval), a po premisleku vidimo, da bi to program zgolj zapletlo.

Rešitev dela za zagnane pa je takšna:

import networkx, matplotlib G = networkx.Graph() for oseba, znani in znanci.items(): for oseba2 in znani: G.add_edge(oseba, oseba2) networkx.draw_spring(G) matplotlib.pyplot.savefig("znanci.png")

Last modified: Sunday, 13 November 2011, 12:26 AM