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])
if self.b1 == (self.b2-1):
self.neni.append("0")
elif self.b2 == (self.b1-1):
self.neni.append("6")
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ě
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)
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])):