Μεταφορά στο εθνικό δίκαιο / Αποσυμπίεση Λειτουργία (αντίστροφο της zip);

ψήφοι
363

Έχω μια λίστα με τις πλειάδες 2-θέση και θα ήθελα να τα μετατρέψετε σε 2 λίστες όπου το πρώτο περιέχει το πρώτο στοιχείο σε κάθε πλειάδα και η δεύτερη λίστα κατέχει το δεύτερο στοιχείο.

Για παράδειγμα:

original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
# and I want to become...
result = (['a', 'b', 'c', 'd'], [1, 2, 3, 4])

Είναι μια ενσωματωμένη λειτουργία που κάνει αυτό;

Δημοσιεύθηκε 21/08/2008 στις 03:29
πηγή χρήστη
Σε άλλες γλώσσες...                            


14 απαντήσεις

ψήφοι
576

zipΕίναι δική αντίστροφο της! Εφόσον χρησιμοποιείτε το ειδικό φορέα *.

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]

Ο τρόπος με τον οποίο δουλεύει αυτό είναι καλώντας zipμε τα επιχειρήματα:

zip(('a', 1), ('b', 2), ('c', 3), ('d', 4))

... εκτός από τα επιχειρήματα περάσει zipάμεσα (αφού μετατράπηκε σε μια πλειάδα), οπότε δεν υπάρχει λόγος να ανησυχείτε για τον αριθμό των επιχειρημάτων πάρει πάρα πολύ μεγάλο.

Απαντήθηκε 21/08/2008 στις 03:36
πηγή χρήστη

ψήφοι
24

Θα μπορούσατε επίσης να κάνετε

result = ([ a for a,b in original ], [ b for a,b in original ])

Θα πρέπει να αναβαθμίσουν καλύτερα. Ειδικά αν Python κάνει καλό για να μην την επέκταση των Η κατανόηση λίστα, εκτός εάν απαιτείται.

(Παρεμπιπτόντως, κάνει ένα 2-tuple (ζεύγος) από τις λίστες, όχι μια λίστα των πλειάδων, όπως το zipκάνει.)

Αν γεννήτριες, αντί της πραγματικής λίστες είναι εντάξει, αυτό θα το κάνουμε αυτό:

result = (( a for a,b in original ), ( b for a,b in original ))

Οι γεννήτριες δεν πάρει κανείς στη λίστα μέχρι να ρωτήσετε για κάθε στοιχείο, αλλά από την άλλη πλευρά, κρατούν αναφορές στην αρχική λίστα.

Απαντήθηκε 24/08/2008 στις 16:07
πηγή χρήστη

ψήφοι
19

Αν έχετε λίστες που δεν είναι το ίδιο μήκος, μπορεί να μην θέλετε να χρησιμοποιήσετε zip σύμφωνα με Patricks απάντηση. Αυτό λειτουργεί:

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]

Αλλά με διαφορετικές λίστες μήκος, φερμουάρ περικόπτει κάθε στοιχείο με το μήκος του συντομότερου καταλόγου:

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])
[('a', 'b', 'c', 'd', 'e')]

Μπορείτε να χρησιμοποιήσετε το χάρτη χωρίς τη λειτουργία για να γεμίσει τα κενά αποτελέσματα με Κανένας:

>>> map(None, *[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])
[('a', 'b', 'c', 'd', 'e'), (1, 2, 3, 4, None)]

zip () είναι οριακά πιο γρήγορα όμως.

Απαντήθηκε 02/01/2011 στις 11:14
πηγή χρήστη

ψήφοι
12

Μου αρέσει να χρησιμοποιώ zip(*iterable)(το οποίο είναι το κομμάτι του κώδικα που ψάχνετε) σε προγράμματα μου έτσι:

def unzip(iterable):
    return zip(*iterable)

Θεωρώ unzipπιο ευανάγνωστο.

Απαντήθηκε 01/03/2014 στις 13:00
πηγή χρήστη

ψήφοι
2

Είναι μόνο ένας άλλος τρόπος για να το κάνουμε, αλλά με βοήθησε πολύ ώστε να μπορώ να το γράψω εδώ:

Έχοντας αυτή τη δομή δεδομένων:

X=[1,2,3,4]
Y=['a','b','c','d']
XY=zip(X,Y)

Εχοντας ως αποτέλεσμα:

In: XY
Out: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]

Η πιο pythonic τρόπος για να το αποσυμπιέσετε και να πάει πίσω στο πρωτότυπο είναι αυτό κατά τη γνώμη μου:

x,y=zip(*XY)

Αλλά αυτό επιστρέψει μια πλειάδα έτσι εάν χρειάζεστε μια σειρά που μπορείτε να χρησιμοποιήσετε:

xy=(list(x),list(y))
Απαντήθηκε 26/01/2016 στις 08:45
πηγή χρήστη

ψήφοι
8
>>> original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> tuple([list(tup) for tup in zip(*original)])
(['a', 'b', 'c', 'd'], [1, 2, 3, 4])

Δίνει μια πλειάδα των καταλόγων όπως στην ερώτηση.

list1, list2 = [list(tup) for tup in zip(*original)]

Αποσυμπιέζει τις δύο λίστες.

Απαντήθηκε 05/03/2016 στις 09:08
πηγή χρήστη

ψήφοι
0

Ένας άλλος τρόπος για να σκεφτούμε unzipή να transposeμετατρέπει μια λίστα των γραμμών σε μια λίστα των στηλών.

pitchers = [('Nolan', 'Ryan'), ('Roger', 'Clements'), ('Schilling','Curt')]
first_names, last_names = zip(*pitchers)
In [45]: first_names
Out[45]: ('Nolan', 'Roger', 'Schilling')
In [46]: last_names
Out[46]: ('Ryan', 'Clements', 'Curt')
Απαντήθηκε 18/04/2018 στις 01:27
πηγή χρήστη

ψήφοι
1

Δεδομένου ότι επιστρέφει πλειάδες (και μπορεί να χρησιμοποιήσει τους τόνους της μνήμης), το zip(*zipped)τέχνασμα φαίνεται να είναι πιο έξυπνοι από ό, τι χρήσιμο, για μένα.

Εδώ είναι μια λειτουργία που πραγματικά θα σας δώσει το αντίστροφο του φερμουάρ.

def unzip(zipped):
    """Inverse of built-in zip function.
    Args:
        zipped: a list of tuples

    Returns:
        a tuple of lists

    Example:
        a = [1, 2, 3]
        b = [4, 5, 6]
        zipped = list(zip(a, b))

        assert zipped == [(1, 4), (2, 5), (3, 6)]

        unzipped = unzip(zipped)

        assert unzipped == ([1, 2, 3], [4, 5, 6])

    """

    unzipped = ()
    if len(zipped) == 0:
        return unzipped

    dim = len(zipped[0])

    for i in range(dim):
        unzipped = unzipped + ([tup[i] for tup in zipped], )

    return unzipped
Απαντήθηκε 11/06/2018 στις 12:35
πηγή χρήστη

ψήφοι
-1

Αυτό είναι το πώς μπορείτε να μεταφέρουν μια πλειάδα 2x4 σε μια πλειάδα 4x2.

 >>> tuple(zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])) 

αποτέλεσμα

[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
Απαντήθηκε 30/06/2018 στις 02:23
πηγή χρήστη

ψήφοι
0

Καμία από τις προηγούμενες απαντήσεις αποτελεσματικά παρέχει την απαιτούμενη έξοδο, η οποία είναι μια πλειάδα των καταλόγων , παρά μια λίστα των πλειάδων . Για την πρώτη, που μπορείτε να χρησιμοποιήσετε tupleμε map. Εδώ είναι η διαφορά:

res1 = list(zip(*original))              # [('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
res2 = tuple(map(list, zip(*original)))  # (['a', 'b', 'c', 'd'], [1, 2, 3, 4])

Επιπλέον, οι περισσότερες από τις προηγούμενες λύσεις αναλάβει Python 2.7, όπου zipεπιστρέφει μια λίστα και όχι ένα iterator.

Για Python 3.x, θα χρειαστεί να περάσει το αποτέλεσμα σε μια λειτουργία, όπως listκαι tupleνα εξαντλήσει το iterator. Για τη μνήμη αποδοτική επαναλήπτες, μπορείτε να παραλείψετε το εξωτερικό listκαι tupleκαλεί για τις αντίστοιχες λύσεις.

Απαντήθηκε 23/08/2018 στις 16:36
πηγή χρήστη

ψήφοι
0

Αν και zip(*seq)είναι πολύ χρήσιμο, μπορεί να είναι ακατάλληλο για πολύ καιρό ακολουθίες καθώς θα δημιουργήσει μια πλειάδα των τιμών που πρέπει να περάσει μέσα. Για παράδειγμα, έχω εργαστεί με ένα σύστημα συντεταγμένων με πάνω από ένα εκατομμύριο εγγραφές και βρείτε signifcantly πιο γρήγορα να δημιουργήσουν οι αλληλουχίες άμεσα.

Μια γενική προσέγγιση θα ήταν κάτι σαν αυτό:

from collections import deque
seq = ((a1, b1, …), (a2, b2, …), …)
width = len(seq[0])
output = [deque(len(seq))] * width # preallocate memory
for element in seq:
    for s, item in zip(output, element):
        s.append(item)

Αλλά, ανάλογα με το τι θέλετε να κάνετε με το αποτέλεσμα, η επιλογή της συλλογής μπορεί να κάνει μια μεγάλη διαφορά. Στην συγκεκριμένη περίπτωση μου χρήση, χρησιμοποιώντας σύνολα και καμία εσωτερική βρόχου, είναι αισθητά πιο γρήγορα από όλες τις άλλες προσεγγίσεις.

Και, όπως και άλλοι έχουν σημειωθεί, εάν κάνετε αυτό με σύνολα δεδομένων, θα μπορούσε να έχει νόημα να χρησιμοποιήσει NumPy ή Pandas συλλογές αντ 'αυτού.

Απαντήθηκε 26/09/2018 στις 13:08
πηγή χρήστη

ψήφοι
2

naive προσέγγιση

def transpose_finite_iterable(iterable):
    return zip(*iterable)  # `itertools.izip` for Python 2 users

λειτουργεί το πρόστιμο σε πεπερασμένες iterable (π.χ. αλληλουχίες όπως list/ tuple/ str) του (δυνητικά άπειρο) iterables η οποία μπορεί να απεικονισθεί όπως

| |a_00| |a_10| ... |a_n0| |
| |a_01| |a_11| ... |a_n1| |
| |... | |... | ... |... | |
| |a_0i| |a_1i| ... |a_ni| |
| |... | |... | ... |... | |

όπου

  • n in ℕ,
  • a_ijαντιστοιχεί στο jοστό στοιχείο i-ου iterable,

και μετά την εφαρμογή transpose_finite_iterableπαίρνουμε

| |a_00| |a_01| ... |a_0i| ... |
| |a_10| |a_11| ... |a_1i| ... |
| |... | |... | ... |... | ... |
| |a_n0| |a_n1| ... |a_ni| ... |

Python παράδειγμα τέτοιων περίπτωση κατά την οποία a_ij == j,n == 2

>>> from itertools import count
>>> iterable = [count(), count()]
>>> result = transpose_finite_iterable(iterable)
>>> next(result)
(0, 0)
>>> next(result)
(1, 1)

Αλλά δεν μπορούμε να χρησιμοποιήσουμε transpose_finite_iterableκαι πάλι για να επιστρέψετε στην δομή της αρχικής iterableγιατί resultείναι μια άπειρη iterable των πεπερασμένων iterables ( tuples στην περίπτωσή μας):

>>> transpose_finite_iterable(result)
... hangs ...
Traceback (most recent call last):
  File "...", line 1, in ...
  File "...", line 2, in transpose_finite_iterable
MemoryError

Λοιπόν, πώς μπορούμε να αντιμετωπίσουμε αυτή την περίπτωση;

... και εδώ έρχεται η deque

Μετά θα ρίξουμε μια ματιά σε έγγραφα της itertools.teeλειτουργίας , υπάρχει Python συνταγή ότι με κάποια τροποποίηση μπορεί να βοηθήσει στην περίπτωσή μας

def transpose_finite_iterables(iterable):
    iterator = iter(iterable)
    try:
        first_elements = next(iterator)
    except StopIteration:
        return ()
    queues = [deque([element])
              for element in first_elements]

    def coordinate(queue):
        while True:
            if not queue:
                try:
                    elements = next(iterator)
                except StopIteration:
                    return
                for sub_queue, element in zip(queues, elements):
                    sub_queue.append(element)
            yield queue.popleft()

    return tuple(map(coordinate, queues))

ας ελέγξουμε

>>> from itertools import count
>>> iterable = [count(), count()]
>>> result = transpose_finite_iterables(transpose_finite_iterable(iterable))
>>> result
(<generator object transpose_finite_iterables.<locals>.coordinate at ...>, <generator object transpose_finite_iterables.<locals>.coordinate at ...>)
>>> next(result[0])
0
>>> next(result[0])
1

Σύνθεση

Τώρα μπορούμε να ορίσουμε γενικά τη λειτουργία για την εργασία με iterables από αυτά iterables των οποίων είναι πεπερασμένοι και άλλα από αυτά είναι δυνητικά απεριόριστη χρήση functools.singledispatchδιακοσμητής όπως

from collections import (abc,
                         deque)
from functools import singledispatch


@singledispatch
def transpose(object_):
    """
    Transposes given object.
    """
    raise TypeError('Unsupported object type: {type}.'
                    .format(type=type))


@transpose.register(abc.Iterable)
def transpose_finite_iterables(object_):
    """
    Transposes given iterable of finite iterables.
    """
    iterator = iter(object_)
    try:
        first_elements = next(iterator)
    except StopIteration:
        return ()
    queues = [deque([element])
              for element in first_elements]

    def coordinate(queue):
        while True:
            if not queue:
                try:
                    elements = next(iterator)
                except StopIteration:
                    return
                for sub_queue, element in zip(queues, elements):
                    sub_queue.append(element)
            yield queue.popleft()

    return tuple(map(coordinate, queues))


def transpose_finite_iterable(object_):
    """
    Transposes given finite iterable of iterables.
    """
    yield from zip(*object_)

try:
    transpose.register(abc.Collection, transpose_finite_iterable)
except AttributeError:
    # Python3.5-
    transpose.register(abc.Mapping, transpose_finite_iterable)
    transpose.register(abc.Sequence, transpose_finite_iterable)
    transpose.register(abc.Set, transpose_finite_iterable)

η οποία μπορεί να θεωρηθεί ως δική αντίστροφο του (μαθηματικοί αποκαλούν αυτό το είδος των λειτουργιών «involutions» ) στην κατηγορία των δυαδικών φορέων πάνω σε πεπερασμένα μη κενά iterables.


Ως μπόνους singledispatchσης μπορούμε να χειριστούμε numpyπίνακες όπως

import numpy as np
...
transpose.register(np.ndarray, np.transpose)

και στη συνέχεια να το χρησιμοποιήσετε σαν

>>> array = np.arange(4).reshape((2,2))
>>> array
array([[0, 1],
       [2, 3]])
>>> transpose(array)
array([[0, 2],
       [1, 3]])

Σημείωση

Από transposeεπιστρέφει iterators και αν κάποιος θέλει να έχει ένα tupleαπό lists, όπως στο ΕΠ - αυτό μπορεί να γίνει επιπρόσθετα με mapενσωματωμένη λειτουργία όπως

>>> original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> tuple(map(list, transpose(original)))
(['a', 'b', 'c', 'd'], [1, 2, 3, 4])

Διαφήμιση

Έχω προσθέσει γενικευμένη λύση για lzτη συσκευασία από την 0.5.0έκδοση που μπορεί να χρησιμοποιηθεί σαν

>>> from lz.transposition import transpose
>>> list(map(tuple, transpose(zip(range(10), range(10, 20)))))
[(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), (10, 11, 12, 13, 14, 15, 16, 17, 18, 19)]

PS

Δεν υπάρχει λύση (τουλάχιστον προφανής) για το χειρισμό των δυνητικά άπειρο iterable δυνητικά άπειρο iterables, αλλά αυτή η περίπτωση είναι λιγότερο συχνές όμως.

Απαντήθηκε 21/12/2018 στις 10:46
πηγή χρήστη

ψήφοι
0

Εξετάστε τη χρήση more_itertools.unzip .

Απαντήθηκε 02/01/2019 στις 19:30
πηγή χρήστη

ψήφοι
0
original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]

#unzip 
a1 , a2 = zip(*original)
#make tuple with two list
result=(list(a1),list(a2))
result

αποτέλεσμα = ([ 'a', 'b', 'c', 'd'], [1, 2, 3, 4])

Απαντήθηκε 12/04/2019 στις 02:18
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more