===== Komentáře k programům ===== * Při hodnocení vašich semestrálek jsem narazil na řadu pěkných kódů, ale také na kódy neefektivní * Na této stránce ukážu několik příkladů a komentářů a nápadů, jak kód vylepšit. * Následující příklady jsou vzaty z odevzdaných kódů bez uvedení autora kódu. ==== Generování permutací ==== * V tomto programu autor generuje permutace 4 ze 6, 5 ze 7 a 6 z 8. * Pro každou kombinaci používá několik vnořených for cyklů. * Kód sice funguje, ale není obecný - pro generování 10 ze 6 by autor musel dopsat dalších 10 vnořených cyklů. * Řešení: použít univerzální generování permutací a dané délkce. Viz moje poslední cvičení. def init(self, glob, count): self.codename = "slozite_generovani" self.glob = glob self.test = count if count == 4: for a in range(6): for b in range(6): for c in range(6): for d in range(6): self.S.append([a,b,c,d]) if count == 5: for a in range(7): for b in range(7): for c in range(7): for d in range(7): for e in range(7): self.S.append([a,b,c,d,e]) if count == 6: for a in range(8): for b in range(8): for c in range(8): for d in range(8): for e in range(8): for f in range(8): self.S2.append([a,b,c,d,e,f]) ==== Používání stringů ve formě čísel ==== * Výsek většího programu, ve kterém se do pole ''neni'' přidávají řetězce "0" a "6" if self.b1 == (self.b2-1): self.neni.append("0") elif self.b2 == (self.b1-1): self.neni.append("6") * O kousek dále však vidíme, že s prvky pole ''neni'' se pracuje jako s čísly: for i in self.neni: i = int(i) self.jes.remove(i) * Toto je velmi neefektivní, zejména přetypování řetězce na int je časově náročná. * Řešením by bylo rovnou do pole ''neni'' dávat čísla. * Další neefektivita spočívá ve volání jes.remove(i), což má mazat i-tý prvek v poli jes. Mazání prvků je rychlé pouze pro poslední prvek, ale v případě mazání prvků v prostřed poli je to výpočetně náročné. * Řešením by bylo vytvořit pomocné pole, které bude mít stejnou délku jako jes, pak vytvořit jes2 postupným přdáváním: # pokud toRemove[i] = 0, pak i-ty prvek nechame, jinak ho smazeme toRemove = [0] * len(self.jes) # nasledujici kod nastavuje toRemove: if self.b1 == (self.b2-1): toRemove[0] = 1 elif self.b2 == (self.b1-1): toRemove[6] = 1 # a tady jednoduse 'promazeme' jes tak, ze vztvorime nove pole: jes2 = [] for i in range(len(jes2)): if toRemove[i] == 0: jes2.append(jes[i]) jes = jes2 # a je to ! ==== Podmínky na nesprávném místě ==== * podmnínky, zvláště ve vnořených cyklech mohou zpomalit nebo zrychlit kod. Např. zde: m = 0 for a in range(10): for b in range(100): for c in range(20): if not c == a: m += 1 * Podmínka ''if not c == a'' je umístěna špatně, neboť se vykonává 20x (počet iterací nejvnořenějšího cyklu), ale přitom její výsledek je možné určit již v druhém cyklu. * S počítáme se, kolikrát se podmínka vykoná: cnt = 0 m = 0 for a in range(10): for b in range(100): for c in range(20): cnt +=1 if not c == a: m += 1 print(m, cnt) * je to m=19000, cnt=20000, tj. ''if'' pomínka se musela vyhodnotit 20 000 krát! * Lepší (rychlejší) řešení: nejprve iterovat pro 'a' a 'c', pak vyhodnotit podmínku, a teprve pak iterovat pro 'b': cnt = 0 m = 0 for a in range(10): for c in range(20): cnt += 1 if not c == a: for b in range(100): m += 1 print(m, cnt) * Výsledek: m=19000, cnt=200, tj. ''if'' podnínka se vykonala pouze 200 krát. To je mimochodem dáno velikostí cyklu pro ''b''. ==== Používání append pro pole předem známé délky ==== * Operace append na poli se jednoduše používá, avšak --- v závislosti na typu jejich prvků --- může být výpočetně náročná. * append je vhodné používat tehdy, pokud dopředu nevíme jaká bude výsledná velikost pole, případně je těžké to určit. * Naopak, pokud umíme velikost výsledného pole jednoznačně určit, je lepší vytvořit celé pole a pouye do něj přistupovat, např. přes index * V tomto programu se prochází pole ''test'' a podle nějaké podmínky se vytváří pole ''mask'' a to buď přidáním 1 nebo 0 * Je jedno, co obsahují pole ''g'' a ''tr'', protože podmínka obsahuje ''if'' i ''else'', tj. vždy se vykoná append. Tedy, v každé iteraci se do pole ''mask'' přidá jedna hodnota * Výsledná velikost pole ''mask'' je tedy shodná s velikostí pole ''test''. mask = [] for i in range(test): # count black points and mark used position if (g[i]==tr[i]): black+=1 mask.append(1) else: mask.append(0) * Řešení: rovnou vytvořit pole ''mask'', naplnit nulama, a přiřazovat jedničku v prvním ''if'': * Všimněte si, že není nutné používat část ''else:'' a to proto, že pole ''mask'' je již defaultně naplněno nulama. #pole nul mask = [ 0 ] * len(test) for i in range(test): # count black points and mark used position if (g[i]==tr[i]): black+=1 mask[i] = 1 ==== Neopodstatnění continue ==== for i in range(len(cand)): tr = cand[i] res = mind.secondevaluate(self,gues,tr) if(b == res[0] and res[1] == w): newcand.append(tr) continue else: continue ==== Neopodstatnění list ==== element = [0,0,0,0,0] while(True): candidates.append(list(element)) if(element[4]!=6): element[4]+=1 ==== Pozor na metodu index() ==== for i in range(self.n): if temp1[i] != '' and temp1[i] in temp2: whitecounter += 1 temp2[temp2.index(temp1[i])] = '' ==== Hledani maxima ===== #maximum v radku for i in range (len(matrix)): maximum=-1000000000000000000000000000000000000000000000000000000 for j in range (len(matrix[i])):