2010-12-15 26 views
3

Ich bin neu bei Python und ich liebe es, aber ich frage mich, ob es eine bessere Möglichkeit gibt, ein paar Listenmanipulationen zu machen.Gibt es eine bessere Möglichkeit, solche Listen zu erstellen?

Dieser ist relativ gesund, aber es scheint, als ob ich eine eingebaute Funktion verpasst haben könnte.

def zip_plus(source_list, additional_list): 
    """ 
    Like zip but does plus operation where zip makes a tuple 

    >>> a = [] 
    >>> zip_plus(a, [[1, 2], [3, 4]]) 
    >>> a 
    [[1, 2], [3, 4]] 
    >>> zip_plus(a, [[11, 12], [13, 14]]) 
    >>> a 
    [[1, 2, 11, 12], [3, 4, 13, 14]] 
    """ 
    if source_list: 
     for i, v in enumerate(additional_list): 
      source_list[i] += v 
    else: 
     source_list.extend(additional_list) 

Dieser ist Hacky und schwer zu lesen, alle Ideen auf tut es saubere oder mehr pythonic?

def zip_join2(source_list, additional_list): 
    """ 
    Pretty gross and specialized function to combine 2 types of lists of things, 
    specifically a list of tuples of something, list 
    of which the something is left untouched 

    >>> a = [] 
    >>> zip_join2(a, [(5, [1, 2]), (6, [3, 4])]) 
    >>> a 
    [(5, [1, 2]), (6, [3, 4])] 
    >>> zip_join2(a, [(5, [11, 12]), (6, [13, 14])]) 
    >>> a 
    [(5, [1, 2, 11, 12]), (6, [3, 4, 13, 14])] 
    """ 
    if source_list: 
     for i, v in enumerate(additional_list): 
      source_list[i] = (source_list[i][0], source_list[i][1] + v[1]) 
    else: 
     source_list.extend(additional_list) 

Antwort

1

List Verständnis mit Tupel Entpacken und Boolean Logik.

zip_plus:

from itertools import izip_longest 
def zip_plus(first, second): 
    return [(a or []) + (b or []) for a, b in izip_longest(first, second)] 

print zip_plus([], [[1, 2], [3, 4]]) 
print zip_plus([[1, 2], [3, 4]], [[11, 12], [13, 14]]) 
print zip_plus([[1, 2], [3, 4]], [[11, 12]]) 
print zip_plus([[1, 2]], [[11, 12], [13, 14]]) 

zip_join2:

from itertools import izip_longest 
def zip_join2(first, second): 
    return [(a or c or 0, (b or []) + (d or [])) for (a, b), (c, d) in \ 
       izip_longest(first, second, fillvalue=(None, None))] 

print zip_join2([], [(5, [1, 2]), (6, [3, 4])]) 
print zip_join2([(5, [1, 2]), (6, [3, 4])], [(5, [11, 12]), (6, [13, 14])]) 

Die 0 deckt den Fall, dass a = 0 ist und c gleich Keine. Einiges davon lässt mich auch zusammenzucken.

+0

Ich mag das (a oder []) + (b oder []) Idiom auch, und werde es wahrscheinlich auch in meinem Algorithmus verwenden, danke, dass du dir die Zeit genommen hast. –

+0

@Scott B, gern geschehen. Ich liebe diese Art von Problemen und die Lösungen, die Menschen bieten. Ich nehme jeden Tag etwas von SO weg. Ihre Verwendung von "Doctest" -Stil Docstrings hat mich dazu inspiriert, "Doctest" mehr und nicht nur "Pytest/Unittest" zu verwenden. :-) – kevpie

4
def zip_plus(first, second): 
    return [x+y for (x,y) in zip(first, second)] 

def zip_join2(first, second): 
    return [(x[0], x[1]+y[1]) for (x,y) in zip(first, second)] 
+0

Dies gekoppelt mit Forschung, die mich zu izip_longest führte (da ich in der Lage sein würde, meine Arbeit auf einer akkumulierenden Basis zu tun) sieht gut aus, danke! –

+1

Auch das benötigte die if-Blöcke aus anderen Antworten: return [x + y wenn x und y sonst x oder y für (x, y) in izip_longest (first, second)] –

3

Zuerst mehr Pythonic, sein I-Eingänge mutiert vermeiden würde.

Zweitens möchten Sie wahrscheinlich etwas mehr wie ein dict anstelle einer Liste von Tupeln für Ihre zip_join2 Funktion. Wie so:

>>> a = {5 : [1,2], 6 : [3,4]} 
>>> b = {5 : [11,12], 6 : [13,14]} 
>>> for k,v in b.iteritems(): 
...  a[k].extend(v) 
>>> a = {5: [1,2,11,12], 6: [3,4,13,14]} 

könnten Sie wollen auch einen defaultdict (aus den Sammlungen Modul) mit zu berücksichtigen, falls der zweiten Wörterbuchschlüssel nicht in dem ersten hat.

+0

Ja, ich mochte die Idee nicht, Eingänge zu mutieren , Danke für die Rückmeldung. –

1
def zip_plus(source_list, additional_list): 
    return map(lambda a, b: a + b if a and b else a or b, source_list, additional_list) 

def zip_join2(source_list, additional_list): 
    return map(lambda x, y: (x[0], x[1] + y[1]), source_list, additional_list) 

map arbeitet parallel.

+0

Ich würde nicht sagen, dass es "parallel arbeitet" ... das klingt für mich so, als würde es die Berechnung über mehrere Kerne verteilen. – perimosocordiae

+0

Ich beziehe mich auf diesen Kommentar in den verknüpften Dokumenten: '_function_ ... wird auf die Elemente aus allen iterables parallel angewendet' – sje397

+0

Anwenden der gleichen Stil von, wenn zu Ihrer Version von zip_join2 auch benötigt wird. Ich mag diese Antwort auch. –

Verwandte Themen