2013-09-05 12 views
6

Mam nadzieję, że napiszę funkcję join_lists, aby pobrać dowolną liczbę list i połączyć je. Na przykład, jeśli dane wejściowe sąŁączyć dowolną liczbę list w funkcji w Pythonie

m = [1, 2, 3] 
n = [4, 5, 6] 
o = [7, 8, 9] 

potem zadzwonię print join_lists(m, n, o), zwróci [1, 2, 3, 4, 5, 6, 7, 8, 9]. Rozumiem, że powinienem używać *args jako argumentu w join_lists, ale nie wiem, jak połączyć dowolną liczbę list. Dzięki.

+0

Nie trzeba pisać tej funkcji, tylko 'od łańcucha importu itertools'. –

Odpowiedz

8

Jednym ze sposobów byłoby to (za pomocą reduce) bo aktualnie czuć funkcjonalny:

import operator 
from functools import reduce 
def concatenate(*lists): 
    return reduce(operator.add, lists) 

Jednak metoda lepiej funkcjonalny podano w odpowiedzi Marcina:

from itertools import chain 
def concatenate(*lists): 
    return chain(*lists) 

chociaż równie dobrze można bezpośrednio użyj itertools.chain(*iterable_of_lists).

Sposób proceduralny:

def concatenate(*lists): 
    new_list = [] 
    for i in lists: 
     new_list.extend(i) 
    return new_list 

golfed wersję: j=lambda*x:sum(x,[]) (faktycznie nie używać tego).

+0

dzięki! Co powiesz na to, że nie importujesz żadnych modułów i używasz tylko podstawowych narzędzi? – alittleboy

+4

@alittleboy Biblioteka standardowa to podstawowe narzędzie. – Marcin

+3

Pierwsza forma będzie mieć kwadratową złożoność i utworzyć n list pośrednich. – Marcin

3

Można użyć sum() z pustym liście jako start argumentu:

def join_lists(*lists): 
    return sum(lists, []) 

Na przykład:

>>> join_lists([1, 2, 3], [4, 5, 6]) 
[1, 2, 3, 4, 5, 6] 
+2

Nie. Suma jest niewłaściwym narzędziem do tej pracy. – Marcin

+1

Dlaczego? Myślę, że to wygląda dobrze. – rlms

+5

To rozwiązanie jest dobre tylko dla bardzo krótkich list, ma kwadratową złożoność. –

13

Chociaż można użyć czegoś, co wywołuje __add__ sekwencyjnie, że jest bardzo źle rzecz (na początek możesz stworzyć tyle nowych list, ile list zawiera dane wejściowe, co kończy się kwadratową złożonością).

standardowe narzędzie jest itertools.chain:

def concatenate(*lists): 
    return itertools.chain(*lists) 

lub

def concatenate(*lists): 
    return itertools.chain.from_iterable(lists) 

powoduje przywrócenie generator, który daje w wyniku każdego elementu wykazach sekwencji. Jeśli jest to potrzebne w postaci listy, użyj list: list(itertools.chain.from_iterable(lists))

Jeśli domagać się robi to "ręcznie", a następnie użyć extend:

def concatenate(*lists): 
    newlist = [] 
    for l in lists: newlist.extend(l) 
    return newlist 

Właściwie nie używać extend w ten sposób - to wciąż nieefektywne, ponieważ musi nadal rozszerzać oryginalną listę. „Prawo” sposób (jest to nadal bardzo zły sposób):

def concatenate(*lists): 
    lengths = map(len,lists) 
    newlen = sum(lengths) 
    newlist = [None]*newlen 
    start = 0 
    end = 0 
    for l,n in zip(lists,lengths): 
     end+=n 
     newlist[start:end] = list 
     start+=n 
    return newlist 

http://ideone.com/Mi3UyL

Musisz pamiętać, że to wciąż kończy się robi jak wiele operacji kopiowania, ponieważ istnieją całkowite szczeliny w listach.Tak więc nie jest to lepsze niż użycie list(chain.from_iterable(lists)) i jest prawdopodobnie gorsze, ponieważ list może korzystać z optymalizacji na poziomie C.


Wreszcie, oto wersja użyciu extend (nieoptymalne) w jednej linii, przy użyciu zmniejszają:

concatenate = lambda *lists: reduce((lambda a,b: a.extend(b) or a),lists,[]) 
+0

Czy PEP8 nie stwierdza, że ​​chociaż * możemy * zapisać pętlę w jednej linii, nie powinniśmy? Po prostu jestem wybredna. – SethMMorton

+0

@SethMMorton Stwierdza również, że głupia konsystencja jest hobgoblinem małych umysłów, o ile pamiętam. Z pewnością uważam, że jest to bardziej czytelne dla jednego wyrazu. – Marcin

+0

Haha. To też prawda. – SethMMorton

-1

inny sposób:

>>> m = [1, 2, 3] 
>>> n = [4, 5, 6] 
>>> o = [7, 8, 9] 
>>> p = [] 
>>> for (i, j, k) in (m, n, o): 
...  p.append(i) 
...  p.append(j) 
...  p.append(k) 
... 
>>> p 
[1, 2, 3, 4, 5, 6, 7, 8, 9] 
>>> 
+0

Działa tylko wtedy, gdy wszystkie listy są dokładnie tej samej długości. – Duncan

+0

O tak. Dzięki za wskazanie. – sachitad

-1

Lub może być logiczne zamiast podejmowania zmienna (tutaj "z") równa pierwszej liście przekazanej do funkcji "join_lists" , a następnie przypisanie pozycji do listy (a nie samej listy) do nowej listy, do której będziesz wtedy można dodać elementy inne listy:

m = [1, 2, 3] 
n = [4, 5, 6] 
o = [7, 8, 9] 

def join_lists(*x): 
    z = [x[0]] 
    for i in range(len(z)): 
     new_list = z[i] 
    for item in x: 
     if item != z: 
      new_list += (item) 
    return new_list 

następnie

drukowania (join_lists (m, n, o)

będzie Wydajność:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

0

To wydaje się działać dobrze:

def join_lists(*args): 
    output = [] 
    for lst in args: 
     output += lst 
    return output 

Zwraca nową listę wszystkich przedmiotów z poprzednich listach. Czy użycie + nie jest odpowiednie dla tego rodzaju przetwarzania list?

Powiązane problemy