2015-05-21 22 views
5
def partition(n, iterable): 
    p = izip_longest(*([iter(iterable)] * n)) 
    r = [] 
    for x in p: 
     print(x) #I added this 
     s = set(x) 
     s.discard(None) 
     r.append(list(s)) 
    return r 

Questo è in realtà in un annuncio di lavoro su SO e essendo un principiante ho pensato che fosse interessante. Così si ottiene un output come il seguente:Cosa fa questa funzione? (Iteratori di Python)

partition(5, L) 
(1, 2, 3, 4, None) 
Out[86]: [[1, 2, 3, 4]] 

Per me questo è già fonte di confusione perché ho pensato izip_longest(*([iter(iterable)] * n)) sarebbe eseguire la funzione izip_longest su un elenco di n iteratori identici così mi sarei aspettato prima una potenza di (1,1,1,1,1) e poi un uscita di (2,2,2,2,2) e così via.

versione così a corto di mia domanda, è quello che sta succedendo con questa linea:

p = izip_longest(*([iter(iterable)] * n)) 

analizzarlo avrei pensato [iter (iterable)] * n crea una lista di lunghezza n di iterables identici tutto puntando alla stessa cosa - questo è ciò che fa sulla riga di comando, ma non sembra essere quello che fa qui in base all'output stampato sopra.

Inoltre, ho pensato che * all'inizio fosse ...longest(*... poiché la lista è di lunghezza sconosciuta, ma non penso che abbia perfettamente senso. Che cos'è il primo simbolo * all'interno della chiamata di funzione? Non sembra che stia semplicemente indicando una lunghezza sconosciuta di argomenti ...

Quindi alla fine della giornata sono completamente perso. Qualcuno può guidarmi attraverso questa sintassi?

Grazie mille per qualsiasi input!


Grazie per tutte le risposte utili, tutti. Non sono sicuro di voler affrontare una risposta o una domanda qui, ma a me sembra che questa comprensione delle liste farà la stessa cosa per le liste e le tuple (mi rendo conto che gli iteratori si applicherebbero anche a dizionari, corsi personalizzati, altre cose ... .)

[L[i*n:(i+1)*n] for i in range(int(ceil(len(L)/float(n)))) ] 
+1

hai letto [Come fa 'zip (* [iter (s)] * n)' work in Python] (http://stackoverflow.com/questions/2233204/how- fa-zipitersn-work-in-python)? –

+0

interrompe una grande lista in elenchi di dimensioni minori di dimensioni N .... compilando Nessuno nel caso in cui la lunghezza della lista non sia divisibile in modo uniforme per N ... l'unica sottolista che dovrebbe contenere qualsiasi 'Nessuna' è l'ultima lista –

+0

Aggiungi una 'print (list (p))' per vedere cosa 'izip_longest()' ha fatto. – martineau

risposta

6

Data:

>>> li 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] 

C'è una idioma Python comune dell'uso di zip in combinazione con iter e * operator per partizionare un elenco di un elenco semplice in un elenco di elenchi di lunghezza n:

>>> n=3 
>>> zip(*([iter(li)] * n)) 
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 14), (15, 16, 17), (18, 19, 20)] 

Tuttavia, se n non è un multiplo della lunghezza complessiva, l'elenco definitivo viene troncato:

>>> n=4 
>>> zip(*([iter(li)] * n)) 
[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11), (12, 13, 14, 15), (16, 17, 18, 19)] 

È possibile utilizzare izip_longest di utilizzare la lista completa compilato con un valore selezionato per le liste sub incomplete:

>>> list(izip_longest(*([iter(li)] * n))) 
[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11), (12, 13, 14, 15), (16, 17, 18, 19), (20, None, None, None)] 
+0

buona risposta spiegando perché stava ottenendo None e perché sta usando izip_longest :) +1 –

+0

@dawg ringrazia Un sacco. Questo è davvero carino – sunny

+1

Si noti che a causa del modo in cui vengono rimossi gli extra 'Nessuno', quelli iterabili contenenti' None' non sono supportati da questa funzione. Ad esempio, 'partition (2, [1,2, None, 4,5])' dà '[[1, 2], [4], [5]]'. Sarebbe stato più efficace usare un valore sentinella personalizzato, credo. – jpmc26

6

iter(my_list) converte un elenco in un iterabile (che è quella in cui gli elementi sono consumati come sono visti)

[my_iter]*5 crea un nuovo elenco di [my_iter,my_iter,my_iter,my_iter,my_iter] in cui tutti i punti 's il my_iter allo stesso iteratore esatta

zip(*[my_iter,my_iter,my_iter,my_iter,my_iter]) 

è uguale

zip(my_iter,my_iter,my_iter,my_iter,my_iter) 

(il simbolo scompatta semplicemente un elenco/tupla), che fondamentalmente solo restituisce un elenco 2d 5xlen(my_list)//5

si potrebbe semplificare con zip normale

#this method will have no `None` entries 
new_list_partitioned = zip(*[iter(big_list)]*N) + [big_list[-(len(big_list)%N):],] 
+0

se guardi la mia domanda, quella parte che ho ricevuto. Quello che non ho ottenuto è stato il motivo per cui * di fronte [iter (... – sunny

+0

disfa l'elenco ... –