Un esercizio in Python

A me piace molto il C++, ci lavoro e lo insegno. Ma riconosco che sia un linguaggio “un po’ complicato” (eufemismo). Per tante cose di tutti giorni, serve qualcosa di più semplice. Come sapete, recentemente mi sto appassionando al Python: e siccome la maniera migliore per fissare quello che uno impara è di metterlo per iscritto e provare a spiegarlo agli altri, oggi si parla di Python. Vi presento un piccolo esercizio in Python in cui svilupperemo le nostre abilità con la programmazione funzionale.

Supponiamo di avere un file pieno di numeri interi separati da virgole. Il file è però un pochino disordinato: su una linea ci possono essere un numero variabile di numeri, e tra un numero e l’altro e tra le virgole ci possono essere un numero variabile di spazi. Obiettivo: leggere tutti i numeri e metterli in una lista. Facile facile.

Esempio di file in input:

12 , 25, 
34, -15,    17  , 
100, 24

, 37, 99

Comciamo con il leggere tutto il file:

file = open('dati.txt', 'r')
lines = file.readlines()
all = ""
for x in lines :
    all = all + x

lines è una lista di stringhe, una per ogni linea, e con il ciclo le mettiamo tutte insieme.
Poi le splittiamo e infine le trasformiamo in interi:

nums = all.split(',')
intnum = []
for x in nums : 
    intnum.append(int(x))
print intnum

Insomma, facile. Ma tutti quei cicli for… non si può fare in maniera più compatta? Ovviamente si!
Ecco come. Innanzitutto, eliminiamo il primo ciclo for utilizzando la funzione read() che legge tutto in una stringa.

file = open('dati.txt', 'r')
all = file.read()

La stringa all adesso contiene tutto il file in una sola stringa. Adesso proviamo a fare lo split e a transformare tutto in numeri in un colpo solo:

intnum = map(int, all.split(','))
print intnum

La funzione map() applica la funzione passata come primo argomento, ovvero int(), a tutti gli elementi della lista passata come secondo argomento, ovvero al risultato di all.split(‘,’), e produce dunque una lista di interi.

A questo punto potremmo anche far tutto in una sola linea:

print map(int, open('dati.txt','r').read().split(','))

Alternativamente, invece della map() potete usare la list comprehension:

print [int(x) for x in open('dati.txt','r').read().split(',')]

Voilà, tutto in una linea!

Esercizio per casa: supponete di avere un file di configurazione con delle “proprietà”, ogni proprietà può avere assegnato un valore numerico. Ad esempio:

pippo = 15,
pluto = 25, paperino = 104, 
paperone = 75, qui, quo, qua

Nel file qui quo e qua non hanno alcun valore assegnato, quindi supponiamo che il vaolre di default per loro sia 0.
L’esercizio consiste nel leggere il file e produrre un dizionario {key,value}. L’output del programma sul file precedente dovrebbe essere:

{'pippo': 15, 'paperino': 104, 'pluto': 25, 'qua': 0, 'paperone': 75, 'qui': 0, 'quo': 0}

Cercate di farlo con il codice più breve e compatto possibile!

Buon divertimento! (poi posterò la mia soluzione, e non è affatto detto che la mia sarà la più “compatta”)

PS: nella prima versione di questo post, leggevo il file con readlines() solo per fare una join() successiva. In realtà basta fare read() per leggere l’intero file, e quindi ho editato la seconda parte del post.

Posta un commento o usa questo indirizzo per il trackback.

Commenti

  • Roberto Gambuzzi  Il 8 gennaio 2014 alle 09:54

    http://pastebin.com/PhfDi1nt

    non ho considerato il valore assegnato come intero, ma ho tenuto il valore come stringa.

    • Roberto Gambuzzi  Il 8 gennaio 2014 alle 10:01

      oppure, considerando i valori numerici…
      data = “””pippo = 15,
      pluto = 25, paperino = 104,
      paperone = 75, qui, quo, qua
      “””
      import re
      print dict(((x, int(‘0’+y)) for x,y in re.findall(r'(\w+)(?:\s*=\s*(.*?)[,|$])?’, data, re.I|re.S)))

  • juhan  Il 9 gennaio 2014 alle 14:31

    Ottima idea quella di Roberto!
    Un’estensione a “”” concepito per i commenti (in particolare per documentare cosa fa la funzione) 🙂
    Notare che WordPress trasforma il codice di ‘ e ” in qualcosa di più bello che da errore.
    Però, domanda: dobbiamo imparare a usare le espressioni regolari come i Perlisti?
    Già che ci sono: Emacs (ma anche vi(m)): si usano ancora, i giovani devono impararli?
    Ne va dei miei prossimi post, mi sa… 🙄

    • Roberto Gambuzzi  Il 9 gennaio 2014 alle 14:55

      Le regex male non fanno. Secondo me tutti dovrebbero saperle usare, ricordandosi che “quando si ha 1 problema e si usano le regex ci si trova con 2 problemi” 🙂 Scherzi a parte spesso risolvono problemi che altrimenti richiederebbero tanto codice (e quindi tanti possibili bug).
      Per la questione IDE io sono una anima in pena e non vi so dare risposte. Diciamo che ho usato dal pspad, al vim, passando per ninjaIDE, PyCharm e sublime text e ancora non so cosa usare…

  • glipari  Il 9 gennaio 2014 alle 15:41

    Ecco la mia soluzione, senza regex:

    p = open('dati2.txt','r').read().split(',')
    d = dict ({a.strip() : int(b) for [a,b] in 
               [x.split('=') for x in filter(lambda x : x.find('=') > -1, p)]
               }.items() + 
              {a.strip() : 0 for a in 
               filter(lambda x : x.find('=') == -1, p) 
               }.items())
    

    Forse si può fare un po’ più corta con le if nelle list comprehension a sostituire i filter()…

    Esiste forse altro editor all’infuori di Emacs? 🙂

Trackback

  • Dov’è il modulo? | Ok, panico su 4 gennaio 2014 alle 12:38

    […] Una richiesta a seguito del post Intro all’uso dei moduli in Python. […]

  • Cast –quasi– in Python | Ok, panico su 13 gennaio 2014 alle 10:56

    […] post Un esercizio in Python ha dato il via a un paio di commenti che se fossi ripetitivo scriverei ancora una volta […]

  • Modificare il testo | Ok, panico su 15 gennaio 2014 alle 11:33

    […] subito. Anche perché non è detto che serva tutta la loro potenzialità. Come nei post precedenti qui (e commenti) e qui ci sono casi più […]

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.

%d blogger hanno fatto clic su Mi Piace per questo: