===== 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])):