Opomba: Gre za izpit, ki so ga pisali študenti drugostopenjskega študija Kognitivnih znanosti in tretjestopenjskega študija Bioznanosti. Ti študenti torej niso računalnikarji, kljub temu pa lahko pridejo nekatere naloge prav tudi brucom VSŠ, ki se učijo programirati.

LihiNe7

def lihoNe7(s): naj = min(s)-1 for e in s: if e%2!=0 and e%7!=0 and e>naj: naj = e return naj

Edini trik tule je, da moramo v začetku postaviti naj na neko vrednost. Če ga postavimo na nekaj, kar je manjše od najmanjšega, bo to gotovo OK. To iz nekega razloga, ki ga ob tej nalogi ne bom razlagal, ni ravno optimalna rešitev, je pa preprosta.

Tole je rešitev, ki bi jo navadno uporabil jaz:

def lihoNe7a(s): return max(e for e in s if e%2!=0 and e%7!=0)

Takole pa bi napisal, če bi imel dober dan.

def lihoNe7b(s): return max(e for e in s if (e%2)*(e%7))

Sodi-Lihi

Če je vsota dveh zaporednih števil soda, sta bodisi obe sodi bodisi obe lihi... in v tem primeru takoj vrnemo False. Če se to ne zgodi (a počakamo, da zanka steče do konca, Bog obvaruj pisati else:!), vrnemo True.

def sodiLihi(s): for i in range(len(s)-1): if (s[i]+s[i+1])%2 == 0: return False return True

Rešitev s trikom: če je s prazen ali pa ima le en element, je OK. Sicer pa delamo tole: racunamo, kakšen je ostanek vsot po dveh zaporednih členov pri deljenju z 2. Lahko je 0 ali 1. Hočemo, da so vsi 1 ... se pravi, da mora biti minimum enak 1.

def sodiLihi_a(s): return len(s)<2 or min( (i+j)%2 for i, j in zip(s, s[1:]) ) == 1

Indeksiraj

Tudi tule ni nič drugega kot par trikov s predavanj. Pomisliti je potrebno le, kako daleč spustiti zanko (razmisli, čemu ravno len(s)+1-k!)

def indeksiraj(s, k): indeksi = {} for i in range(len(s)+1-k): b = s[i:i+k] if b in indeksi: indeksi[b].append(i) else: indeksi[b] = [i] return indeksi

Tule je pa še lepša rešitev, ki uporablja defaultdict, slovar, ki sam doda elemente, ki manjkajo.

import collections def indeksiraj_a(s, k): indeksi = collections.defaultdict(list) for i in range(len(s)+1-k): indeksi[s[i:i+k]].append(i) return indeksi

Drugi del naloge je trivialen - presek množice ključev delimo z unijo.

def podobnost(i1, i2): return float(len(set(i1.keys()).intersection(i2.keys())))/len(set(i1.keys()).union(i2.keys()))

Anagrami (iz izpita za študente kognitivnih znanosti)

Naloga ima veliko rešitev; klasična bi bila ta, da štejemo, kolikokrat se pojavi katera črka v kateri besedi in potem to primerjamo (to je čisto tako kot, ko smo na predavanjih/vajah šteli pogostosti besed, le da tu štejemo pogostosti črk). Pa bodimo zato v tej rešitvi inovativnejši: črke obeh besed uredimo po abecedi in če dobimo isto, sta besedi anagrama.

def anagram(b1, b2): return sorted(b1)==sorted(b2)

URLji (iz izpita za študente kognitivnih znanosti)

Rešitev je preprost regularni izraz.

import re re_URL = re.compile("(\w+)://([^/]+)(/.*)?") def razbijURL(url): return re_URL.match(url).groups()

Težavico povzročijo le URLji, pri kateri je pot povsem prazna in ne vsebuje niti poševnice; v tem primeru bo regularni izraz vrnil None namesto praznega niza. Ena rešitev - pa upam, da ne najlepša - je takšna.

import re re_URL = re.compile("(\w+)://([^/]+)(/.*)?") def razbijURL(url): return tuple(x or "" for x in re_URL.match(url).groups())

Golf (iz izpita za študente Bioznanosti)

Preberimo podatke, zložimo števila udarcev igralcev, rojenih 1980 ali kasneje, v nov seznam upostevani in potem izračunajmo poprečje.

def golf(fname): f = open(fname) f.readline() leta = f.readline().split() udarci = f.readline().split() upostevani = [] for leto, udarcev in zip(leta, udarci): if int(leto) >= 1980: upostevani.append(float(udarcev)) return sum(upostevani) / (len(upostevani) or 1)

V programu sta dva drobna trikca. V seznam upoštevanih dajemo necela števila. Tako ali tako bi jih morali pretvoriti iz nizov in čeprav gre za cela števila, uporabimo float namesto int, da si prihranimo pretvarjanje kasneje pri deljenju.

Drugi trik se pojavi v deljenju. Seznam upostevani bi bil lahko tudi prazen in v tem primeru je len(upostevani) enak 0. Da ne bi zašli v deljenje z 0, dodamo or 1. Tale trik deluje le v Pythonu, v drugih jezikih (pa tudi v Pythonu) bi dosegli isti učinek z max(len(upostevani), 1); kadar je len(upostevani) enak 0, to pomeni max(0, 1). V tem primeru bo tudi sum(upostevani) enak 0, dobili bomo 0/1 in to je seveda 0. Če je len(upostevani) enak 1 ali več, pa je max(len(upostevani), 1) toliko kot len(upostevani).

GEO

Rešitev: Genes: 59619, Organism: Oryza sativa

Takole pa se pride do nje (po najkrajši, ne pa nujno najlažji poti - ideja je pa približno ta).

import obiGEO info = obiGEO.GDSInfo() r = max((info["gene_count"], info) for info in info.values()) print "Genes: %d, Organism: %s" % (r[0], r[1]["sample_organism"])
Zadnja sprememba: sreda, 10. avgust 2011, 10.21