2016-01-09 12 views
11

Ho due elenchi, list1 e list2.Unisci elenchi in Python posizionando ogni ennesimo elemento da un elenco e gli altri da un altro?

Qui len(list2) << len(list1).

Ora voglio fondere entrambe le liste tali che ogni elemento ennesima della lista finale è da list2 e gli altri di list1.

Ad esempio:

list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] 

list2 = ['x', 'y'] 

n = 3 

Ora la lista finale dovrebbe essere:

['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h'] 

Qual è il modo più Pythonic per raggiungere questo obiettivo?

Desidero aggiungere tutti gli elementi di list2 all'elenco finale, l'elenco finale dovrebbe includere tutti gli elementi da list1 e list2.

+0

Credo che l'output che hai postato qui sia per 'n = 2' not' n = 3', nop? –

+0

@IronFist Ho detto 3 ° elemento not index = 3? – ofnowhere

+0

Quali vincoli si collocano sulla dimensione di list2? Stai passando in rassegna la lista2 o aggiungendoli alla lista1 finché non sono esauriti? Questo non è un problema chiaro. – polarise

risposta

1

E la soluzione seguente? Tuttavia non ho uno migliore ...

>>> list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] 
>>> list2 = ['x', 'y'] 
>>> n = 2 
>>> for i in range(len(list2)): 
...  list1.insert(n, list2[i]) 
...  n += 3 
...  
... 
>>> list1 
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h'] 

n è 2 perché l'indice di terzo elemento in un elenco è 2, dal momento che inizia da 0.

7

Per conservare l'elenco originale, si potrebbe provare la seguente:

result = copy.deepcopy(list1) 
index = n - 1 
for elem in list2: 
    result.insert(index, elem) 
    index += n 

risultato

['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h'] 
10

Fare la lista più ampia di Itera tor lo rende facile prendere più elementi per ogni elemento della lista più piccola:

list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] 
list2 = ['x', 'y'] 
n = 3 

iter1 = iter(list1) 
res = [] 
for x in list2: 
    res.extend([next(iter1) for _ in range(n - 1)]) 
    res.append(x) 
res.extend(iter1) 

>>> res 
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h'] 

Questo evita insert che può essere costoso per le grandi liste, perché ogni volta l'intero elenco deve essere ricreato.

+2

Semplicemente curioso, qualsiasi motivo per non usare 'iter1.next()' e preferiamo 'next (iter1)' su di esso? –

+8

Python 3. Usa sempre 'next (obj)' perché funziona con Python 2 ** e ** 3. –

0
list(list1[i-1-min((i-1)//n, len(list2))] if i % n or (i-1)//n >= len(list2) else list2[(i-1)//n] for i in range(1, len(list1)+len(list2)+1)) 

Decisamente non pithonic, ma ho pensato che potrebbe essere divertente farlo in un solo liner. Più leggibile (? Davvero) Versione:

list(
    list1[i-1-min((i-1)//n, len(list2))] 
     if i % n or (i-1)//n >= len(list2) 
     else 
    list2[(i-1)//n] 
     for i in range(1, len(list1)+len(list2)+1) 
) 

In sostanza, un po 'di armeggiare intorno con indici e determinare quali lista e quale indice di prendere elemento successivo da.

2

Utilizzando lo itertools module e il supplemento more_itertools package, è possibile costruire una soluzione iterabile in un paio di modi diversi. In primo luogo le importazioni:

import itertools as it, more_itertools as mt 

Questo primo sembra il più pulito, ma si basa su more_itertools.chunked().

it.chain(*mt.roundrobin(mt.chunked(list1, n-1), list2)) 

Questo utilizza solo more_itertools.roundrobin(), la cui attuazione è preso dalla documentazione itertools, quindi se non si ha accesso a more_itertools si può semplicemente copiare da soli.

mt.roundrobin(*([iter(list1)]*(n-1) + [list2])) 

alternativa, questo fa quasi la stessa cosa come il primo campione senza utilizzare alcuna more_itertools funzioni specifico d'. Fondamentalmente, grouper può sostituire chunked, ma in alcuni casi aggiungerà None alla fine, quindi lo incorporo in it.takewhile per rimuoverli. Naturalmente, se lo si utilizza su elenchi che contengono effettivamente None, si fermerà una volta raggiunti tali elementi, quindi fai attenzione.

it.takewhile(lambda o: o is not None, 
    it.chain(*mt.roundrobin(mt.grouper(n-1, list1), list2)) 
) 

Ho provato questi su Python 3.4, ma credo che questi esempi di codice dovrebbero funzionare anche in Python 2.7.

+0

Replicando l'elenco iteratore e usando 'roundrobin' per far progredire ciascuno di essi. – pylang

-1

Forse ecco un'altra soluzione, suddividere l'indice list1 quindi aggiungere l'elemento di list2 in list1.

>>> list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] 
>>> list2 = ['x', 'y'] 
>>> n = 3 
>>> for i in range(len(list2)): 
...  list1 = list1[:n*(i+1) - 1] + list(list2[i]) + list1[n*(i+1)-1:] 
... 
>>> list1 
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h'] 
+0

@downvoter, cura di spiegare? – zangw

0

Ancora un altro modo, che calcolano i passi fetta:

list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] 
list2 = ['x', 'y'] 
n = 3 

res = [] 
m = n - 1 
start, end = 0, m 
for x in list2: 
    res.extend(list1[start:end]) 
    res.append(x) 
    start, end = end, end + m 
res.extend(list1[start:]) 

>>> res 
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h'] 
0
list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] 
list2 = ['x', 'y'] 
n = 3 
new = list1[:] 

for index, item in enumerate(list2): 
    new[n * (index + 1) - 1: n * (index + 1) - 1] = item 

print(new) 
0

ammiro l'uso di @ David Z di more_itertools. Gli aggiornamenti per gli strumenti in grado di semplificare la soluzione:

import more_itertools as mit 

n = 3 
groups = mit.windowed(list1, n-1, step=n-1) 
list(mit.flatten(mit.interleave_longest(groups, list2))) 
# ['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h'] 

Sommario: list2 è essere alternate in in gruppi da list1 e, infine, appiattito in un unico elenco.

Note

  1. groups: n-1 dimensioni finestre scorrevoli, per esempio [('a', 'b'), ('c', 'd'), ('e', 'f'), ('g', 'h')]
  2. interleave_longest è attualmente equivalente a roundrobin
  3. None è l'fillvalue predefinito. Opzionalmente rimuovere con filter(None, ...)
Problemi correlati