2013-05-16 8 views
26

voglio generare un elenco in Python come segue -python di comprensione per la produzione di due valori in un'iterazione

[1, 1, 2, 4, 3, 9, 4, 16, 5, 25 .....] 

Avreste capito, non è altro che n, n*n

ho provato a scrivere come una lista di comprensione in Python come segue -

lst_gen = [i, i*i for i in range(1, 10)] 

Ma facendo questo, dà un errore di sintassi.

Quale sarebbe un buon modo per generare l'elenco sopra tramite la comprensione delle liste?

+1

che ti capita illeggibili, soluzioni Oneliner. Avviso tardivo dato: P – ytpillai

risposta

32

Uso itertools.chain.from_iterable:

>>> from itertools import chain 
>>> list(chain.from_iterable((i, i**2) for i in xrange(1, 6))) 
[1, 1, 2, 4, 3, 9, 4, 16, 5, 25] 

o si può anche usare una funzione generator:

>>> def solve(n): 
...  for i in xrange(1,n+1): 
...   yield i 
...   yield i**2 

>>> list(solve(5)) 
[1, 1, 2, 4, 3, 9, 4, 16, 5, 25] 
+1

più bello del mio :) come al solito: P –

5
lst_gen = sum([(i, i*i) for i in range(1, 10)],()) 

oh Devo dire la somma probabilmente infrange la regola un'iterazione :(

+3

Mentre funziona, usare 'sum' in questo modo fornisce prestazioni quadratiche e quindi è un'abitudine in qualche modo pericolosa. – DSM

+0

yeah itertools sarebbe stato meglio, ma mi piace un po 'il trucco a volte: P –

+0

@DSM, perdona la mia ignoranza, perché usare 'sum()' con una lista di comprensione (di tuple) dare prestazioni quadratiche? Parte della mia domanda è, quale aspetto di "questa via" è il problema? – LarsH

5

Comprensione delle liste genera uno elemento alla volta. Le opzioni disponibili sono, invece, di cambiare il ciclo di generare solo un valore per volta:

[(i//2)**2 if i % 2 else i//2 for i in range(2, 20)] 

o per la produzione di tuple poi appiattire l'elenco utilizzando itertools.chain.from_iterable():

from itertools import chain 

list(chain.from_iterable((i, i*i) for i in range(1, 10))) 

uscita:

>>> [(i//2)**2 if i % 2 else i//2 for i in range(2, 20)] 
[1, 1, 2, 4, 3, 9, 4, 16, 5, 25, 6, 36, 7, 49, 8, 64, 9, 81] 
>>> list(chain.from_iterable((i, i*i) for i in range(1, 10))) 
[1, 1, 2, 4, 3, 9, 4, 16, 5, 25, 6, 36, 7, 49, 8, 64, 9, 81] 
+3

Non so se dovrei essere affascinato o disgustato dalla prima soluzione –

1

Un'altra opzione:

reduce(lambda x,y: x + [y, y*y], range(1,10), []) 
+0

+1, questa è buona – iruvar

+0

Ciò richiede l'importazione in Python 3. ('functools') – ytpillai

1

Un'altra opzione, potrebbe sembrare perverso di alcuni

>>> from itertools import izip, tee 
>>> g = xrange(1, 11) 
>>> x, y = tee(g) 
>>> y = (i**2 for i in y) 
>>> z = izip(x, y) 
>>> output = [] 
>>> for k in z: 
...  output.extend(k) 
... 
>>> print output 
[1, 1, 2, 4, 3, 9, 4, 16, 5, 25, 6, 36, 7, 49, 8, 64, 9, 81, 10, 100] 
3

È possibile creare una lista di liste quindi utilizzare ridurre a unirsi a loro.

print [[n,n*n] for n in range (10)] 

[[0, 0], [1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81]]

print reduce(lambda x1,x2:x1+x2,[[n,n*n] for n in range (10)]) 

[0, 0, 1, 1, 2, 4, 3, 9, 4, 16, 5, 25, 6, 36, 7, 49, 8, 64, 9, 81]

print reduce(lambda x1,x2:x1+x2,[[n**e for e in range(1,4)]\ 
for n in range (1,10)]) 

[1, 1, 1, 2, 4, 8, 3, 9, 27, 4, 16, 64, 5, 25, 125, 6, 36, 216, 7, 49, 343, 8, 64, 512, 9, 81, 729]

Riduci prende un'espressione callable che accetta due argomenti ed elabora una sequenza iniziando dai primi due elementi. Il risultato dell'ultima espressione viene quindi utilizzato come primo elemento nelle chiamate successive. In questo caso ogni elenco viene aggiunto uno dopo l'altro al primo elenco nell'elenco di elenchi e quindi tale elenco viene restituito come risultato.

di lista implicitamente chiamano mappa con un'espressione lambda utilizzando la variabile e la sequenza definita dalla "per var in sequenza" espressione. Quello che segue è lo stesso tipo di cosa.

map(lambda n:[n,n*n],range(1,10)) 

[[1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81]]

Non sono a conoscenza di un'espressione python più naturale da ridurre.

0
>>> lst_gen = [[i, i*i] for i in range(1, 10)] 
>>> 
>>> lst_gen 
[[1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81]] 
>>> 
>>> [num for elem in lst_gen for num in elem] 
[1, 1, 2, 4, 3, 9, 4, 16, 5, 25, 6, 36, 7, 49, 8, 64, 9, 81] 

Ecco il mio riferimento http://docs.python.org/2/tutorial/datastructures.html

0

Prova questa due fodera

lst = [[i, i*i] for i in range(10)] 
[lst.extend(i) for i in lst] 

Cambio di matematica, se necessario.

ANCORA MEGLIO

#Change my_range to be the number you want range() function of 
start = 1 
my_range = 10 
lst = [i/2 if i % 2 == 0 else ((i-1)/2)**2 for i in range(start *2, my_range*2 - 1)] 
0

Come accennato, itertools è la strada da percorrere. Ecco come lo farei, lo trovo più chiaro:

[i if turn else i*i for i,turn in itertools.product(range(1,10), [True, False])] 
1

La domanda è vecchia, ma solo per il lettore curioso, vi propongo un'altra possibilità: Come indicato sul primo post, si può facilmente fare un paio (io, io ** 2) da un elenco di numeri. Allora vuoi appiattire questa coppia. Quindi basta aggiungere l'operazione di appiattimento nella tua comprensione.

[x for i in range(1, 10) for x in (i,i**2)] 
1

Un poco noto trucco: list comprehensions possibile avere più clausole.

Ad esempio:

>>> [10*x+y for x in range(4) for y in range(3)] 
[0, 1, 2, 10, 11, 12, 20, 21, 22, 30, 31, 32] 

Nel vostro caso particolare, si potrebbe fare:

>>> [x*x if y else x for x in range(5) for y in range(2)] 
[0, 0, 1, 1, 2, 4, 3, 9, 4, 16]