Warning
This page is located in archive. Go to the latest version of this course pages.

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

courses/b3b33alp/cviceni/komentare_k_programum.txt · Last modified: 2021/01/04 11:41 by vonasvoj