2016-04-10 27 views
7

Ho una lista di alcuni elementi, ad es. [1, 2, 3, 4] e un singolo oggetto, ad es. 'a'. Voglio produrre un elenco di tuple con gli elementi dell'elenco nella prima posizione e il singolo oggetto nella seconda posizione: [(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')].Python: elenco zip con un singolo elemento

ho potuto farlo con zip in questo modo:

def zip_with_scalar(l, o): # l - the list; o - the object 
    return list(zip(l, [o] * len(l))) 

Tuttavia, questo mi dà un senso di creazione e la lista inutile di ripetere elemento.

Un'altra possibilità è

def zip_with_scalar(l, o): 
    return [(i, o) for i in l] 

che è molto pulito e divinatorio anzi, ma qui faccio il tutto "manualmente". In Haskell vorrei fare qualcosa di simile

zipWithScalar l o = zip l $ repeat o 

C'è qualche funzione o trick built-in, sia per la zippare con scalare o per qualcosa che mi avrebbe permesso di usare zip ordinaria, vale a dire sorta-di lista infinita?

+3

https://docs.python.org/3/library/itertools.html#itertools.repeat – jonrsharpe

+0

Cosa jonrsharpe detto, ma anche probabilmente vuole riscriverlo come un generatore, piuttosto che una funzione regolare. – OmnipotentEntity

+3

@OnnipotentEntity poichè l'OP sta usando 3.x possono semplicemente 'return zip (l, repeat (o))'; è un iteratore, non c'è bisogno di "cedere". – jonrsharpe

risposta

11

Questa è la cloest alla vostra soluzione Haskell:

import itertools 

def zip_with_scalar(l, o): 
    return zip(l, itertools.repeat(o)) 

Si potrebbe anche usare generatori, che evitano la creazione di una lista come comprensioni fare:

def zip_with_scalar(l, o): 
    return ((i, o) for i in l) 
2

Si potrebbe anche usare zip_longest con un valore di riempimento di o:

from itertools import zip_longest 

def zip_with_scalar(l, o): # l - the list; o - the object 
    return zip_longest(l, [o], fillvalue=o) 

print(list(zip_with_scalar([1, 2, 3, 4] ,"a"))) 

Tieni presente che i valori mutabili utilizzati per o non verranno copiati se si utilizza zip_longest o repeat.

3

È possibile utilizzare il built-in funzione di map:

>>> elements = [1, 2, 3, 4] 
>>> key = 'a' 
>>> map(lambda e: (e, key), elements) 
[(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')] 
0

si può fare molto con poco *

elements = [1, 2, 3, 4] 
single_object = 'a' 

zip(elements, single_object * len(elements)) 
+0

questo funziona solo se il singolo oggetto è una sequenza di solo 1 elemento, sicuramente produrrà risultati indesiderati con qualcos'altro, come un numero per esempio. E l'OP già fa qualcosa di simile – Copperfield

+0

Non è questo fondamentalmente la prima soluzione OP ha dato? – refi64

1

Questo è un lavoro perfetto per la classe itertools.cycle.

from itertools import cycle 


def zip_with_scalar(l, o): 
    return zip(i, cycle(o)) 

Demo:

>>> from itertools import cycle 
>>> l = [1, 2, 3, 4] 
>>> list(zip(l, cycle('a'))) 
[(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')] 
+0

L'argomento di '' cycle'' deve essere un iterable, non è vero? Funziona con '' 'a''' poiché è una stringa, ma non con un oggetto arbitrario. – zegkljan

+0

@zegkljan sì, deve essere iterabile. – styvane

0
lst = [1,2,3,4] 
tups = [(itm, 'a') for itm in lst] 
tups 

> [(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')] 
Problemi correlati