Laboratorio di Python (con Linux)

annuncio pubblicitario
Preliminari
Dizionari
Eratostene
Laboratorio di Python (con Linux)
7a lezione
Giulio Pellitta
Università di Bologna
18, 20 aprile 2012
Giulio Pellitta
Laboratorio di Python (con Linux)
Preliminari
Dizionari
Eratostene
Sommario
1
Preliminari
2
Dizionari
3
Eratostene
Giulio Pellitta
Laboratorio di Python (con Linux)
Preliminari
Dizionari
Eratostene
Iterazione determinata (for con remove)
Questa funzione non restituisce la lista degli interi fino ad minori
di n che non sono quadrati (ad esempio, se rimuoviamo 4 poi
non possiamo rimuovere 16).
def square_remove_wrong(n):
L=range(n)
for i in L:
if i**2 in L: L.remove(i**2)
return L
La seguente invece fa esattamente così.
def square_remove(n):
L=range(n)
for i in L[:]:
if i**2 in L: L.remove(i**2)
return L
Giulio Pellitta
Laboratorio di Python (con Linux)
Preliminari
Dizionari
Eratostene
Dizionari
Un dizionario è un tipo di dato di Python: un’insieme di chiavi
(keys) a cui sono associati dei valori (values).
I dizionari sono indicizzabili da chiavi di qualsiasi tipo, purché
immutabili (niente liste nelle chiavi!).
La lista delle chiavi si ottiene con il metodo keys().
Si può cancellare un’associazione chiave:valore con il comando
del
Riferirsi ad una chiave non esistente causa un errore di runtime.
{} #dizionario vuoto
D={1:'a','b':5,'C':True} #dizionario con tre valori
#('a', 5 e True) associati alle chiavi (1, 'b' e 'C')
for k in D: print D[k]#stampa gli oggetti nel dizionario
1 in D #True
1 in D.keys()#True
Giulio Pellitta
Laboratorio di Python (con Linux)
Preliminari
Dizionari
Eratostene
Crivello di Eratostene
def eratostene_very_easy(n):
L,P=[0,0]+range(2,n+1),[]
for p in L:
if p!=0:
for m in range(2*p,n+1,p):
L[m]=0
P.append(p)
return P
Questa funzione è un’implementazione fedele dell’algoritmo
descritto la scorsa lezione.
Il primo passo è ottenere un programma funzionante che sia
chiaro e fidato.
Le ottimizzazioni vengono dopo.
Giulio Pellitta
Laboratorio di Python (con Linux)
Preliminari
Dizionari
Eratostene
def eratostene_less_easy(n):
L,P=[False,False]+[True]*(n-1),[]
for p in range(2,n**0.5+1): #oppure n/2+1
if L[p]:
for m in range(2*p,n+1,p):
L[m]=False
for i in range(len(L)):
if L[i]: P.append(i)
return P
Se k non è primo allora ha almeno due fattori propri (maggiori
√ di
1); se p è il minimo di questi fattori allora p2 ≤ k ovvero p ≤ k .
Se k non è primo allora 2 · p ≤ k (poiché 2p ≤ p2 ); questo limite
è peggiore dell’altro ma non richiede il calcolo della radice.
Alla fine dei due
√ cicli for annidati L[m]=False sse m = k · p per
qualche p ≤ n e 2 ≤ k ≤ n/p.
Giulio Pellitta
Laboratorio di Python (con Linux)
Preliminari
Dizionari
Eratostene
def eratostene_not_so_easy(n):
L,P=[False,False]+[True]*(n-1),[]
for p in range(2,n**0.5+1):
if L[p]:
for m in range(p**2,n+1,p): #!
L[m]=False
for i in range(len(L)):
if L[i]: P.append(i)
return P
Marcare i multipli più volte è inutile.
I multipli di p da 2p a (p − 1)p vengono marcati nelle iterazioni
precedenti a p.
Giulio Pellitta
Laboratorio di Python (con Linux)
Preliminari
Dizionari
Eratostene
def eratostene_smarter(n):
if n<2: return []
L,P=[False]+[True]*((n-1)/2),[2] #!
for p in range(3,n**0.5+1,2): #!
if L[p/2]: #l'indice sarebbe (p-1)/2 #!
for m in range(p**2,n+1,p+p): #!
L[m/2]=False #!
for i in range(len(L)):
if L[i]: P.append(2*i+1) #!
return P
Possiamo escludere direttamente i pari maggiori di 2.
Se p è un primo dispari allora con la divisione tra interi
p/2 = (p − 1)/2 (per calcolare l’indice non serve sottrarre 1).
Se p ≥ 3 è un primo dispari allora ∀k ≥ 0 2|p2 + (2k + 1)p ;
quindi non serve marcare questi multipli, abbiamo appena
escluso i pari.
Giulio Pellitta
Laboratorio di Python (con Linux)
Preliminari
Dizionari
Eratostene
Usando i dizionari
def eratostene_dictionary(n):
if n<2: return []
D,P={},[2] #!
for p in range(3,n**0.5+1,2):
if p not in D: #!s
for m in range(p**2,n+1,p+p):
D[m]=False #!
for i in range(3,n+1,2):
if i not in D: P.append(i) #!
return P
Possiamo usare un dizionario invece di una lista per tener traccia
di quali numeri sono marcati.
Meno efficiente che con le liste (notare: usiamo solo le chiavi del
dizionario, non i valori).
Giulio Pellitta
Laboratorio di Python (con Linux)
Preliminari
Dizionari
Eratostene
Altri algoritmi
def eratostene_multipli(n):
(multiples,p) = ([],[])
for i in range(2, n+1):
if i not in multiples:
p.append(i)
for j in range(2*i, n+1, i):
multiples.append(j)
return p
Altra possibilità è generare tutti i multipli dei numeri primi man
mano che questi vengono trovati.
Se un numero non è tra i multipli, allora è primo.
Giulio Pellitta
Laboratorio di Python (con Linux)
Preliminari
Dizionari
Eratostene
def trial_division(n):
if n<2: return []
if n==2: return [2]
i,P=0,range(3,n+1,2)
while P[i]<=n**0.5:
j=i+1
while j<len(P):
if P[j]%P[i]==0: del P[j]
j+=1
i+=1
return [2]+P
Altro metodo ancora è dividere i vari numeri per i primi già trovati
(“trial division”, divisione per tentativi).
Se il resto della divisione è zero, allora il dividendo non è primo.
Giulio Pellitta
Laboratorio di Python (con Linux)
Preliminari
Dizionari
Eratostene
Esercizi
1
Definire una funzione “expand” che prende una lista di numeri
non-negativi (da controllare che sia così, come per il flatten la
scorsa lezione) e restituisce una lista in cui ogni numero x
compare bxc volte.
2
Scrivere un programma ricorsivo per il calcolo della successione
di Fibonacci (con valori base 0 e 1) facendo uso dei dizionari.
3
Scrivere un programma per calcolare la frequenza delle lettere
dell’alfabeto in un file di testo.
4
Gioco dell’impiccato (scrivere un programma che sceglie a caso
una parola da un file, ne stampa la lunghezza all’utente e gli
chiede di indovinarla). Esercizio per casa: scrivere la soluzione
in un file chiamato impiccato.cognome.nome.py e mandarlo
via email a [email protected] entro il prossimo
laboratorio (subject email: “impiccato”).
Giulio Pellitta
Laboratorio di Python (con Linux)
Preliminari
Dizionari
Eratostene
Suggerimenti
1
2
3
4
Usare la sostituzione di slice come visto la scorsa lezione.
Inizializzare un dizionario a {0:0,1:1} e fare una chiamata a
funzione solo se l’elemento corrispondente della successione di
Fibonacci non è già nel dizionario (sennò calcolarlo e inserirlo).
Inserire le frequenze assolute in una lista o dizionario. Partire da
questa versione semplificata dell’esercizio della scorsa volta.
def parole_da_file(filename):
(text, W) = (open(filename,"r").readlines(), [])
for line in text:
for s in line.split(): W.append(s)
return W
Mettere in una lista le parole lette da file, sceglierne una a caso e
stamparne la lunghezza. L’utente deve indovinare le lettere della
parola: se dice una lettera non presente ha una penalità e vince
se indovina tutte le lettere senza superare k penalità.
Commentare il codice!
Giulio Pellitta
Laboratorio di Python (con Linux)
Scarica