Python: Liste

Le liste rappresentano sequenze ordinate di oggetti arbitrari.

Avvertimento

Le liste sono mutabili!

Per definire una lista uso le parentesi quadre:

# Una lista di interi (anche ripetuti)
alcuni_interi = [1, 2, 1, 1, 9]

# Una lista di stringhe
proteine_uniprot = ["Y08501", "Q95747"]

# Una lista mista
cose = ["Y08501", 0.13, "Q95747", 0.96]

# Una lista di liste
lista_di_liste = [
    ["Y08501", 120, 520],
    ["Q95747", 550, 920],
]

# La lista vuota
una_lista_vuota = []

Avvertimento

Le liste possono contenere elementi ripetuti:

[3, 3, 3, "a", "a", "a"] != [3, "a"]

e l’ordine degli elementi conta:

[1, 2, 3] != [3, 2, 1]

Operazioni

Ritorna Operatore Significato
list range(int, [int]) Restituisce una lista di interi
int len(list) Restituisce la lunghezza della lista
list list + list Concatena le due liste
list list * int Replica la lista
bool object in list Contolla se un oggetto arbitrario appare nella lista
list list[int:int] Estrae una sotto-lista
list list[int] = object Sostituisce un elemento della lista

Esempio. Uso range() per costruire una lista di interi:

>>> lista = range(0, 5)
>>> print lista
[0, 1, 2, 3, 4]

range(5) fa la stessa cosa.


Esempio. La sostituzione di un elemento funziona solo se l’indice corrisponde ad un elemento gia’ esistente:

lista = [0, 1, 2, 3, 4]

lista[0] = "primo"
print lista                         # ["primo", 1, 2, 3, 4]

lista[-1] = "ultimo"
print lista                         # ["primo", 1, 2, 3, "ultimo"]

lista[100] = "oltre l'ultimo"       # Errore!

Esercizi

  1. Creare una lista vuota. Controllare che sia vuota con len().

  2. Creare una lista con i primi cinque interi non-negativi: 0, 1, etc. usando range().

  3. Creare una lista con cento elementi 0.

    Hint: replicate una lista con un solo elemento.

  4. Date:

    lista_1 = range(10)
    lista_2 = range(10, 20)
    

    concatenare le due liste e mettere il risultato in una nuova lista lista_completa. Quanto vale? E’ uguale al risultato di range(20)?

  5. Creare una lista con tre stringhe: "sono", "una", "lista". Poi stampare a schermo tipo e lunghezza dei tre elementi, uno per uno.

  6. Data:

    lista = [0.0, "b", [3], [4, 5]]
    
    1. Quanto e’ lunga lista?

    2. Di che tipo e’ il primo elemento di lista?

    3. Quanto e’ lungo il secondo elemento di lista?

    4. Quanto e’ lungo il terzo elemento di lista?

    5. Quanto vale l’ultimo elemento di lista? Quanto e’ lungo?

    6. La lista ha un elemento di valore "b"?

    7. La lista ha un elemento di valore 4?

      Hint: usate in per controllare.

  7. Che differenza c’e’ tra le seguenti “liste”?:

    lista_1 = [1, 2, 3]
    lista_2 = ["1", "2", "3"]
    lista_3 = "[1, 2, 3]"
    

    Hint: la terza e’ una lista?

  8. Quali dei seguenti frammenti sono validi/errati?

    (Dopo ogni punto, cancellate la lista lista con del, per evitare problemi con i punti successivi)

    1. lista = []
    2. lista = [}
    3. lista = [[]]
    4. lista.append(0)
    5. lista = []; lista.append(0)
    6. lista = [1 2 3]
    7. lista = range(3), elemento = lista[3]
    8. lista = range(3), elemento = lista[-1]
    9. lista = range(3), sottolista = lista[0:2]
    10. lista = range(3), sottolista = lista[0:3]
    11. lista = range(3), sottolista = lista[0:-1]
    12. lista = range(3), lista[2] = "due"
    13. lista = range(3), lista[3] = "tre"
    14. lista = range(3), lista[-1] = "tre"
    15. lista = range(3), lista[1.2] = "uno virgola due"
    16. lista = range(3), lista[1] = ["testo-1", "testo-2"]
  9. Data la lista:

    matrice = [
        [1, 2, 3],          # <-- prima riga
        [4, 5, 6],          # <-- seconda riga
        [7, 8, 9],          # <-- terza riga
    ]
    #    ^  ^  ^
    #    |  |  |
    #    |  |  +-- terza colonna
    #    |  |
    #    |  +----- seconda colonna
    #    |
    #    +-------- prima colonna
    

    Come faccio a:

    1. Estrarre la prima riga?
    2. Estrarre il secondo elemento della prima riga?
    3. Sommare gli elementi della prima riga?
    4. Creare una nuova lista con gli elementi della la seconda colonna?
    5. Creare una nuova lista con gli elementi la diagonale maggiore?
    6. Creare una lista concatenando la prima, seconda, e terza riga?

Metodi

Ritorna Metodo Significato
None list.append(object) Aggiunge un elemento alla fine della lista
None list.extend(list) Estende una lista con un’altra lista
None list.insert(int,object) Inserisce un elemento in una posizione arbitraria
None list.remove(object) Rimuove la prima ripetizione di un valore
None list.reverse() Inverte la lista
None list.sort() Ordina la lista
int list.count(object) Conta il numero di ripetizioni di un valore

Avvertimento

Tutti i metodi delle liste (escluso count()):

  • Modificano la lista stessa.
  • Restituiscono None.

Questo comportamento e’ l’esatto opposto di cio’ che accade con i metodi delle stringhe!

Una conseguenza e’ che fare qualcosa come:

print lista.append(10)

non ha senso, perche’ print stampa il risultato di append(), che e’ sempre None!

Per lo stesso motivo non possiamo fare:

lista.append(1).append(2).append(3)

perche’ il primo append() restituisce None – che non e’ una lista, e non possiamo farci append()!


Esempio. append() aggiunge in coda:

lista = range(10)
print lista                         # [0, 1, 2, ..., 9]

lista.append(10)
print lista                         # [0, 1, 2, ..., 9, 10]

Notate come lista sia stata modificata! Se invece faccio:

lista = range(10)
risultato = lista.append(10)

print risultato                     # None

Come ci aspettavamo, append() restituisce None.

Lo stesso vale per extend():

lista = range(10)
risultato = lista.extend(range(10, 20))

print lista                         # [0, 1, 2, ..., 19]
print risultato                     # None

Per inserire elementi in una posizione arbitraria, uso insert():

lista = range(10)
risultato = lista.insert(2, "un altro valore")

print lista                         # [0, 1, "un altro valore", 3, ...]
print risultato                     # None

remove() invece prende un valore, non una posizione:

lista = ["una", "lista", "non", "una", "stringa"]
risultato = lista.remove("una")

print lista                         # ["lista", "non", "stringa"]
print risultato                     # None

Anche sort() e reverse() modificano la lista stessa:

lista = [3, 2, 1, 5, 4]

risultato = lista.reverse()
print lista                         # [4, 5, 1, 2, 1]
print risultato                     # None

risultato = lista.sort()
print lista                         # [1, 2, 3, 4, 5]
print risultato                     # None

Invece count() non modifica affatto la lista, e restituisce un int:

lista = ["a", "b", "a", "b", "a"]
risultato_a = lista.count("a")      # 3
risultato_b = lista.count("b")      # 2
print "ci sono", risultato_a, "a, e", risultato_b, "b"

Esempio. Contrariamente ad append() e soci, la concatenazione non modifica la lista originale:

lista_1 = range(0, 10)
lista_2 = range(10, 20)

# usando la oncatenazione +
lista_completa = lista_1 + lista_2
print lista_1, "+", lista_2, "->", lista_completa

# usando extend()
lista_completa = lista_1.extend(lista_2)
print lista_1, "estesa con", lista_2, "->", lista_completa

Nel primo caso tutto funziona come vorrei; nel secondo lista_1 e’ estesa con lista_2 (che resta invariata), mentre lista_completa vale None.


Avvertimento

Le liste sono mutabili, e contengono riferimenti ad oggetti.

Questi due fatti possono dare luogo ad effetti complicati – che esploriamo nei prossimi esercizi.

Esempio. Questo codice:

sottolista = range(5)
lista = [sottolista]
print lista

crea una lista lista che contiene una lista sottolista come elemento. Quando modifico sottolista, che e’ una lista e quindi e’ mutabile, finisco inavvertitamente per modificare anche lista!:

sottolista.append(5)
print sottolista

print lista

Esempio. Questo codice mostra un’altra anomalia:

lista = range(5)
print lista

finta_copia = lista         # copio solo il *riferimento* a lista!
print finta_copia

lista.append(5)
print lista

print finta_copia           # Ooops!

Questo accade perche’ lista_1 e lista_2 si riferiscono allo stesso oggetto lista. Se voglio creare una copia reale della lista lista, scrivo:

lista = range(5)
print lista

copia_vera = lista[:]
# oppure
# copia_vera = [elem for elem in lista]
print copia_vera

lista.append(5)
print lista

print copia_vera

Esercizi

  1. Inserire nella lista lista prima un intero, poi una stringa, poi una lista.

    Avvertimento

    La lista deve esistere gia’ prima di poterci fare append(), extend(), insert(), etc.. Ad esempio:

    >>> una_lista_che_non_ho_mai_definito.append(0)
    

    da’ errore:

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'una_lista_che_non_ho_mai_definito' is not defined
    
  2. Partendo (per ogni punto) da:

    lista = range(3)
    

    cosa fanno i seguenti frammenti di codice? (Ripartite ogni volta da lista = range(3).)

    1. lista.append(3)
    2. lista.append([3])
    3. lista.extend([3])
    4. lista.extend(3)
    5. lista.insert(0, 3)
    6. lista.insert(3, 3)
    7. lista.insert(3, [3])
    8. lista.insert([3], 3)
  3. Che differenza c’e’ tra:

    lista = []
    lista.append(range(10))
    lista.append(range(10, 20))
    

    e:

    lista = []
    lista.extend(range(10))
    lista.extend(range(10, 20))
    

    Di che lunghezza e’ lista nei due casi?

  4. Che cosa fa questo codice?:

    lista = [0, 0, 0, 0]
    lista.remove(0)
    
  5. Che cosa fa questo codice?:

    lista = [1, 2, 3, 4, 5]
    lista.reverse()
    lista.sort()
    

    Posso riscriverlo cosi’?:

    lista = [1, 2, 3, 4, 5]
    lista.reverse().sort()
    
  6. Data la lista:

    lista = range(10)
    

    mettere in lista_inversa gli elementi di lista in ordine inverso (dall’ultimo al primo) usando reverse(). lista non deve essere alterata.

  7. Data la lista:

    frammenti = [
        "KSYK",
        "SVALVV"
        "GVTGI",
        "VGSSLAEVLKLPD",
    ]
    

    mettere in frammenti_ordinati gli elementi di frammenti ordinati alfanumericamente con sort(). frammenti non deve essere alterata.

  8. (Una Curiosita’ Inutile). Che “struttura” ha questa lista?:

    lista = []
    lista.append(lista)
    

Metodi Stringhe-Liste

Ritorna Metodo Significato
list-of-str str.split(str) Rompe una stringa in una lista di stringhe
str str.join(list-of-str) Ricompone una lista di stringhe in una stringa

Esempio. La lista di stringhe:

tabella = [
    "nome,cognome,numero di premi nobel vinti",
    "Albert,Einstein,1",
    "Marie,Curie,2",
]

che riporta informazioni su personaggi noti in tre colonne separate da virgole ",".

Estraggo i titoli delle colonne dall’intestazione (la prima riga della tabella) con split():

titoli_colonne = tabella[0].split(",")

print titoli_colonne
print type(titoli_colonne)

e calcolo quante colonne ci sono:

num_colonne = len(titoli_colonne)

Esempio. join() e’ utile per ricomporre liste di stringhe, ad esempio:

lista_di_stringhe = ["uno", "due", "tre"] * 100

print type(lista_di_stringhe), lista_di_stringhe

stringa_intera = " ".join(lista_di_stringhe)

print type(stringa_intera), stringa

Avvertimento

Quando uso join(), la lista deve contenere stringhe! Questo non funziona:

" ".join([1, 2, 3])

Esercizi

  1. Data la stringa:

    testo = """The Wellcome Trust Sanger Institute
    is a world leader in genome research."""
    

    mettere le parole di testo in una lista di stringhe. Poi stampare a schermo quante parole contiene.

    Poi mettere in prima_riga la prima riga di testo.

    Fare la stessa cosa con seconda_riga.

    Estrarre la prima parola di seconda_riga e stamparla a schermo.

  2. La tabella di stringhe:

    tabella = [
        "protein | database | domain | start | end",
        "YNL275W | Pfam | PF00955 | 236 | 498",
        "YHR065C | SMART | SM00490 | 335 | 416",
        "YKL053C-A | Pfam | PF05254 | 5 | 72",
        "YOR349W | PANTHER | 353 | 414",
    ]
    

    presa da Saccharomyces Genome Database, rappresenta una lista di (informazioni su) domini identificati nella sequenza di alcune proteine del lievito.

    Ogni riga e’ un dominio, tranne la prima (che fa da intestazione).

    Usando split() ottenere una lista dei titoli delle varie colonne, avendo cura di accertarsi che le stringhe che corrispondono ai titoli non contengano spazi superflui.

    Hint: non e’ necessario usare strip().

  3. Data la lista di stringhe:

    parole = ["parola_1", "parola_2", "parola_3"]
    

    costruire, usando solo join() ed un opportuno delimitatore le seguenti stringhe:

    1. "parola_1 parola_2 parola_3"
    2. "parola_1,parola_2,parola_3"
    3. "parola_1 e parola_2 e parola_3"
    4. "parola_1parola_2parola3"
    5. r"parola_1\parola_2\parola_3"
  4. Data la lista di stringhe:

    versi = [
        "Taci. Su le soglie",
        "del bosco non odo",
        "parole che dici",
        "umane; ma odo",
        "parole piu' nuove",
        "che parlano gocciole e foglie",
        "lontane."
    ]
    

    usare join() per creare una stringa multi-linea con i versi in versi.Il risultato ("poesia") deve essere:

    >>> print poesia
    Taci. Su le soglie
    del bosco non odo
    parole che dici
    umane; ma odo
    parole piu' nuove
    che parlano gocciole e foglie
    lontane.
    

    Hint: che delimitatore devo usare?

List Comprehension

La list comprehension permette di trasformare e/o filtrare una lista.

Data una lista qualunque lista_originale, posso creare una nuova lista che contiene solo gli elementi che soddisfano una certa condizione:

lista_filtrata = [elemento
                  for elemento in lista_originale
                  if condizione(elemento)]

Qui condizione() ce la inventiamo noi.


Esempio. Creo una nuova lista contenente solo i numeri pari da 0 a 9:

numeri = range(10)
numeri_pari = [numero for numero in numeri
               if numero % 2 == 0]
print numeri_pari

Esempio. Data la lista di sequenze nucleotidiche:

sequenze = ["ACTGG", "CCTGT", "ATTTA", "TATAGC"]

tengo solo le sequenze che contengono almeno una adenosina:

sequenze_con_a = [sequenza for sequenza in sequenze
                  if "A" in sequenza]
print sequenze_con_a

Per tenere solo quelle che non contengono adenosina, inverto la condizione:

sequenze_senza_a = [sequenza for sequenza in sequenze
                    if not "A" in sequenza]
print sequenze_senza_a

Esempio. Se ometto la condizione, cosi’:

lista_2 = [elemento for elemento in lista]

ottengo una copia di lista.


Esempio. Uso una lista di liste per descrivere una rete di regolazione tra geni:

microarray = [
    ["G1C2W9", "G1C2Q7", 0.2],
    ["G1C2W9", "G1C2Q4", 0.9],
    ["Q6NMS1", "G1C2W9", 0.8],
    # ^^^^^^    ^^^^^^   ^^^
    #  gene1     gene2   correlazione
]

Ogni lista “interna” ha tre elementi: i primi due sono identificativi di geni di A. Thaliana, il terzo e’ una misura di correlazione tra l’espressione dei due geni in un qualche microarray.

Posso usare una list comprehension per tenere solo le coppie di geni con correlazione alta:

geni_altamente_correlati = \
    [tripla[:-1] for tripla in microarray if tripla[-1] > 0.75]

oppure ottenere i geni che sono altamente coespressi con il gene "G1C2W9":

soglia = 0.75
geni_coespressi = \
    [tripla[0] for tripla in microarray
     if tripla[1] == "G1C2W9" and tripla[-1] >= soglia] + \
    [tripla[1] for tripla in microarray
     if tripla[0] == "G1C2W9" and tripla[-1] >= soglia]

Avvertimento

Il nome della variabile che itera sugli elementi (nell’esempio sopra, elemento) e’ arbitrario. Questo codice:

lista = range(10)
print [x for x in lista if x > 5]

e’ identico a questo:

lista = range(10)
print [y for y in lista if y > 5]

Il nome della variabile, x o y, e’ immateriale.


La list comprehension puo’ essere usata anche per creare una nuova lista che contiene gli elementi di lista_originale trasformati (uno per uno, individualmente) in qualche modo:

lista_trasformata = [trasforma(elemento)
                     for elemento in lista_originale]

Qui trasforma() e’ una “trasformazione” che ci inventiamo noi.


Esempio. Data la lista:

numeri = range(10)

creo una nuova lista con i loro doppi:

doppi = [numero * 2 for numero in numeri]
#        ^^^^^^^^^^
#      trasformazione
print doppi

Esempio. Data la lista di percorsi relativi alla directory data/:

percorsi_relativi = ["aatable", "fasta.1", "fasta.2"]

prefisso il percorso "data/" a ciascun elemento:

percorsi_completi = ["data/" + percorso
                     for percorso in percorsi]
print percorsi_completi

Esempio. Data la lista di sequenze primarie:

sequenze = [
    "MVLTIYPDELVQIVSDKIASNK",
    "GKITLNQLWDIS",
    "KYFDLSDKKVKQFVLSCVILKKDIE",
    "VYCDGAITTKNVTDIIGDANHSYS",
]

metto in una lista nuova lunghezze le lunghezze di ciascuna sequenza, in ordine:

lunghezze = [len(sequenza) for sequenza in sequenze]
print lunghezze

Esempio. Data una lista di stringhe:

atomi = [
    "SER A 96 77.253 20.522 75.007",
    "VAL A 97 76.066 22.304 71.921",
    "PRO A 98 77.731 23.371 68.681",
    "SER A 99 80.136 26.246 68.973",
    "GLN A 100 79.039 29.534 67.364",
    "LYS A 101 81.787 32.022 68.157",
]

che rappresenta (parte della) struttura terziaria di una catena proteica, voglio ottenere una lista di liste che contiene, per ogni residuo (stringa) in atomi, le sue coordinate (tre elementi).

Scrivo:

coordinate = [riga.split()[-3:] for riga in atomi]

ed ottengo:

>>> print coordinate
[
    ["77.253", "20.522", "75.007"],
    ["76.066", "22.304", "71.921"],
    ["77.731", "23.371", "68.681"],
    ["80.136", "26.246", "68.973"],
    ["79.039", "29.534", "67.364"],
    ["81.787", "32.022", "68.157"],
]

Come funziona questo codice? Consideriamo la prima riga di``atomi``:

"SER A 96 77.253 20.522 75.007"

Quando la list comprehension incontra questa riga, fa questo:

riga = "SER A 96 77.253 20.522 75.007"

poi applica la trasformazione riga.split()[-3:], i cui passaggi sono:

>>> print riga.split()
["SER", "A", "96", "77.253", "20.522", "75.007"]
#                  ^^^^^^^^  ^^^^^^^^  ^^^^^^^^
#                     -3        -2        -1

>>> print riga.split()[-3:]
["77.253", "20.522", "75.007"]

quindi il risultato della trasformazione applicata a questa riga e’ la lista:

["77.253", "20.522", "75.007"]

Questa lista viene appesa a coordinate.

A questo punto la list comprehension prende la seconda seconda riga di atomi:

"VAL A 97 76.066 22.304 71.921"

la mette in riga, ed applica la stessa trasformazione, ottenendo la lista:

["76.066", "22.304", "71.921"]

che appende a coordinate.

Poi prende la terza riga di atomi, etc.


Infine, posso combinare filtro e trasformazione per creare una nuova lista che contiene solo gli elementi di lista_originale che soddisfano una certa condizione, ma trasformati in qualche modo:

nuova_lista = [trasforma(elemento)
               for elemento in lista_originale
               if condizione(elemento)]

Esempio. Dati gli interi da 0 a 10, voglio tenere solo quelli pari e dividerli per 3:

pari_diviso_3 = [float(numero) / 3
                 for numero in range(10)
                 if numero % 2 == 0]

Notate che la condizione opera su numero (l’elemento originale della lista oridinale, non trasformato), non su float(numero) / 3.


Avvertimento

La list comprehension costruisce una nuova lista, lasciando l’originale inalterata, sia quando filtro:

numeri = range(10)
numeri_pari = [numero
               for numero in lista_originale
               if numero % 2 == 0]

print numeri, "e' lunga", len(numeri)
print numeri_pari, "e' lunga", len(numeri_pari)

sia quando trasformo:

numeri = range(10)
doppi = [numero * 2 for numero in numeri]

print numeri
print doppi

Esercizi

Avvertimento

Nei prossimi esercizi, se open() da’ errore e’ probabile che non abbiate fatto partire il terminale dalla directory giusta. Ad esempio in questo caso:

>>> righe = open("file/che/non/esiste").readlines()

Python da’ (giustamente) errore:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'file/che/non/esiste'
#                  ^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^
#                  non esiste questo file!        nome del file

Assicuratevi di adattare il percorso in base alla directory nella quale vi trovate.

  1. Data la lista:

    lista = range(100)
    
    1. Creare una nuova lista lista_piu_3 contenente il valore degli elementi di lista piu’ 3. Il risultato deve essere:

      [3, 4, 5, ...]
      
    2. Creare una nuova lista lista_dispari contenente solo gli elementi dispari di lista. Il risultato deve essere:

      [1, 3, 5, ...]
      

      Hint: un intero e’ dispari se e solo se il risultato di:

      numero % 2
      

      e’ 1.

    3. Creare una nuova lista lista_opposti contenente l’opposto aritmetico (l’opposto di x e’ -x) degli elementi di lista. Il risultato deve essere:

      [0, -1, -2, ...]
      
    4. Creare una nuova lista lista_inversi contenente l’inverso aritmetico (l’inverso aritmetico di x e’ \frac{1}{x}) degli elementi di lista. Se l’inverso di un elemento non esiste, l’elemento deve essere ignorato (non comparire in lista_inversi). Il risultato deve essere:

      [1, 0.5, 0.33334, ...]
      

      Hint: l’unico intero senza un inverso e’ 0.

    5. Creare una nuova lista contenente solo il primo e l’ultimo elemento di lista. Il risultato deve essere:

      [0, 99]
      

      Hint: si fa con una list comprehension?

    6. Creare una nuova lista contenente tutti gli elementi di lista tranne il primo e l’ultimo. Il risultato deve essere:

      [1, 2, ..., 97, 98]
      
    7. Contare quanti numeri dispari ci sono in lista. Il risultato deve essere 50.

      Hint: basta usare una list comprehension?

    8. Creare una nuova lista contenente tutti gli elementi di lista divisi per 5 (anche quelli non divisibili per 5!). Il risultato deve essere:

      [0.0, 0.2, 0.4, ...]
      
    9. Creare una nuova lista lista_multipli_5_divisi contenente solo i multipli di 5, ma divisi per 5. Il risultato deve essere:

      [0.0, 1.0, 2.0, ..., 19.0]
      
    10. Creare una nuova lista lista_di_stringhe contenente tutti gli elementi di lista ma convertiti in stringhe. Il risultato deve essere:

      ["0", "1", "2", ...]
      
    11. Contare quante stringhe rappresentanti un numero dispari ci sono in lista_di_stringhe.

    12. Creare una stringa che contenga tutti gli elementi di lista, visti come stringhe, e separati da uno spazio. Il risultato deve essere:

      "0 1 2 ..."
      

      Hint: basta usare una list comprehension?

  2. Per ciascuno dei punti seguenti, scrivere due list comprehension che producano lista_1 da lista_2 e viceversa.

    1. lista_1 = [1, 2, 3]
      lista_2 = ["1", "2", "3"]
      
    2. lista_1 = ["nome", "cognome", "eta'"]
      lista_2 = [["nome"], ["cognome"], ["eta'"]]
      
    3. lista_1 = ["ACTC", "TTTGGG", "CT"]
      lista_2 = [["actc", 4], ["tttgggcc", 6], ["ct", 2]]
      
  3. Data la lista:

    lista = range(10)
    

    quali dei seguenti frammenti sono validi o errati, e cosa fanno?

    1. [x for x in lista]
    2. [y for y in lista]
    3. [y for x in lista]
    4. ["x" for x in lista]
    5. [str(x) for x in lista]
    6. [x for str(x) in lista]
    7. [x + 1 for x in lista]
    8. [x + 1 for x in lista if x == 2]
  4. Data la lista di stringhe dna restituita da:

    dna = open("data/dna-fasta/fasta.1").readlines()
    print dna
    
    1. Creare una nuova lista di stringhe che contenga tutte le stringhe in dna tranne quella di intestazione (la riga che comincia per ">").
    2. Ci sono caratteri di a capo o spazi nella lista di stringhe ottenuta? Se si’, creare una nuova lista di stringhe che sia identica a quella ottenuta, ma dove le stringhe non contengano caratteri di a capo ne’ spazi.
    3. Concatenare in una singola stringa tutte le righe ottenute.
    4. Calcolare la percentuale di citosina e guanina nella sequenza ottenuta.
    5. Calcolare il GC-content della sequenza.
  5. Consideriamo la stringa:

    risultato_cdhit = """\
    >Cluster 0
    0 >YLR106C at 100.00%
    >Cluster 50
    0 >YPL082C at 100.00%
    >Cluster 54
    0 >YHL009W-A at 90.80%
    1 >YHL009W-B at 100.00%
    2 >YJL113W at 98.77%
    3 >YJL114W at 97.35%
    >Cluster 52
    0 >YBR208C at 100.00%
    """
    

    ottenuta raggruppando le strutture primarie del genoma di S. Cerevisiae (preso da SGD) con un software di clustering (CD-HIT).

    risultato_cdhit codifica in forma testuale alcuni cluster di proteine raggruppate in base alla similarita’ delle loro sequenze.

    Un gruppo comincia con la riga:

    >Cluster N
    

    dove N e’ il numero del cluster. I contenuti del cluster sono dati dalle righe successive, ad esempio:

    >Cluster 54
    0 >YHL009W-A at 90.80%
    1 >YHL009W-B at 100.00%
    2 >YJL113W at 98.77%
    3 >YJL114W at 97.35%
    

    rappresenta un gruppo di quattro sequenze, denominato "Cluster 54": di quel gruppo fanno parte la proteina "YHL009W-A" con una similarita’ del 90.80%, la proteina "YHL009-B" con una similarita’ del 100.00%, etc.

    Data risultato_cdhit, usare delle list comprehension per:

    1. Estrarre i nomi dei vari cluster. Il risultato deve essere:

      >>> print nomi_cluster
      ["0", "50", "54", "52"]
      
    2. Estrarre i nomi di tutte le proteine (non importa se ci sono doppioni). Il risultato deve essere:

      >>> print proteine
      ["YLR1106C", "YPL082C", "YHL00W-A", ...]
      
    3. Estrarre le coppie proteina-percentuale per tutte le proteine. il risultato deve essere:

      >>> print coppie_proteina_percentuale
      [["YLR106C", 100.0],
       ["YPL082C", 100.0],
       ["YHL009W-A", 90.8],
       # ...
      ]
      
  6. Il comando:

    righe = open("data/prot-pdb/1A3A.pdb").readlines()
    print " ".join(righe)                   # stampo le righe
    print len(righe)                        # 5472
    

    restituisce una lista di righe del file data/prot-pdb/1A3A.pdb, preso dalla Protein Data Bank. Descrive una proteina di E. Coli.

    Hint: aprite il file con un editor di testo (nano, gedit, quello che preferite) e fatevi un’idea dei contenuti prima di procedere!

    1. Estrarre tutte le righe che cominciano per "SEQRES" e mettere il risultato nella lista righe_seqres.

      Dovrebbero esserci esattamente 48 righe di questo tipo. Il risultato deve somigliare a questo:

      >>> print " ".join(righe_seqres)
      SEQRES   1 A  148  MET ALA ASN LEU PHE LYS LEU GLY ALA GLU ASN ILE PHE
      SEQRES   2 A  148  LEU GLY ARG LYS ALA ALA THR LYS GLU GLU ALA ILE ARG
      SEQRES   3 A  148  PHE ALA GLY GLU GLN LEU VAL LYS GLY GLY TYR VAL GLU
      # ...
      SEQRES  10 D  148  LEU THR ASN ALA LEU ASP ASP GLU SER VAL ILE GLU ARG
      SEQRES  11 D  148  LEU ALA HIS THR THR SER VAL ASP GLU VAL LEU GLU LEU
      SEQRES  12 D  148  LEU ALA GLY ARG LYS
      #          ^       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      #        catena    sequenza primaria della catena
      

      La prima colonna delle righe in righe_seqres e’ sempre "SEQRES" (per costruzione), la terza e’ il nome della catena di 1A3A descritta in quella riga, mentre le colonne dalla quinta in poi descrivono la sequenza primaria della catena stessa.

      1. Estrarre le catene da righe_seqres (non importa se ci sono doppioni).

        Il risultato deve essere:

        >>> print catene
        ["A", ..., "B", ..., "C", ..., "D", ...]
        
      2. Estrarre solo le righe della catena B e metterle in righe_seqres_B. Devono esserci esattamente 12 righe.

      3. Estrarre da righe_seqres_B la sequenza della catena B e metterla in una sola stringa sequenza_B.

        Il risultato deve essere:

        >>> print sequenza_B
        "MET ALA ASN LEU PHE ... ALA GLY ARG LYS"
        
    2. Estrarre da righe tutte le righe che cominciano per "HELIX" e mettere il risultato nella lista righe_helix.

      Devono esserci esattamente 30 righe di questo tipo. Il risultato deve somigliare a questo:

      >>> print " ".join(righe_helix)
      HELIX    1   1 ALA A    9  ASN A   11  5                                   3
      HELIX    2   2 LYS A   21  LYS A   34  1                                  14
      HELIX    3   3 PRO A   40  LEU A   52  5                                  13
      HELIX    4   4 VAL A   68  ARG A   73  5                                   6
      HELIX    5   5 HIS A  111  ALA A  121  1                                  11
      #              ^^^^^^^^^^  ^^^^^^^^^^
      #             inizio elica  fine elica
      

      La prima colonna delle righe in righe_helix e’ sempre "HELIX" (per costruzione). Ogni riga descrive una \alpha-helix della proteina 1A3A.

      La quarta, quinta e sesta colonna descrivono il residuo dal quale parte l’elica: tipo del residuo, catena di riferimento, e posizione del residuo.

      La settima, ottava e nona colonna descrivono il residuo dove finisce l’elica: sempre con tipo, catena e posizione.

      Estrarre una lista info_eliche in cui ogni elemento rappresenta un’elica, e ne contiene la posizione di inizio, la posizione di fine, e la lunghezza.

  7. Data la matrice 3\times 3:

    matrice = [range(0,3), range(3,6), range(6,9)]
    
    1. Mettere in una lista prima_riga la prima riga.
    2. Mettere in una lista prima_colonna la prima colonna.
    3. Creare una matrice sottosopra che contenga le righe di matrice ma sottosopra.
    4. (Difficile.) Creare una matrice palindromo che contenga le colonne di matrice ma da sinistra a destra.
    5. (Difficile.) Ricreare matrice con una sola list comprehension.
  8. (Difficile). Data la lista:

    lista = range(100)
    

    Creare una lista lista_quadrati contenente i quadrati degli elementi di lista. Il risultato deve essere:

    [0, 1, 4, 9, ...]
    

    Poi creare una lista lista_differenze_quadrati che contenga, nella posizione i-esima il valore:

    lista_quadrati[i+1] - lista_quadrati[i]
    

    per tutti, tranne l’ultimo, valore di lista_quadrati. E’ consigliabile usare piu’ di un passaggio, ed eventualmente liste ausiliarie.

    (Che numeri avete ottenuto? Ecco perche’.)