<p>I have a list of 2-item tuples and I'd like to convert them to 2 lists where the first contains the first item in each tuple and the second list holds the second item.</p>

<p><strong>For example:</strong></p>

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

<p>Is there a builtin function that does that?</p>

[{'answer_id': 19343, 'author': 'Patrick', 'author_id': 429, 'author_profile': 'https://Stackoverflow.com/users/429', 'pm_score': 11, 'selected': True, 'text': '<p><a href="http://docs.python.org/library/functions.html#zip" rel="noreferrer"><code>zip</code></a> is its own inverse! Provided you use the special * operator.</p>\n\n<pre><code>&gt;&gt;&gt; zip(*[(\'a\', 1), (\'b\', 2), (\'c\', 3), (\'d\', 4)])\n[(\'a\', \'b\', \'c\', \'d\'), (1, 2, 3, 4)]\n</code></pre>\n\n<p>The way this works is by calling <code>zip</code> with the arguments:</p>\n\n<pre><code>zip((\'a\', 1), (\'b\', 2), (\'c\', 3), (\'d\', 4))\n</code></pre>\n\n<p>… except the arguments are passed to <code>zip</code> directly (after being converted to a tuple), so there\'s no need to worry about the number of arguments getting too big.</p>\n'}, {'answer_id': 25193, 'author': 'Anders Eurenius', 'author_id': 1421, 'author_profile': 'https://Stackoverflow.com/users/1421', 'pm_score': 5, 'selected': False, 'text': "<p>You could also do</p>\n\n<pre><code>result = ([ a for a,b in original ], [ b for a,b in original ])\n</code></pre>\n\n<p>It <em>should</em> scale better. Especially if Python makes good on not expanding the list comprehensions unless needed.</p>\n\n<p>(Incidentally, it makes a 2-tuple (pair) of lists, rather than a list of tuples, like <code>zip</code> does.)</p>\n\n<p>If generators instead of actual lists are ok, this would do that:</p>\n\n<pre><code>result = (( a for a,b in original ), ( b for a,b in original ))\n</code></pre>\n\n<p>The generators don't munch through the list until you ask for each element, but on the other hand, they do keep references to the original list.</p>\n"}, {'answer_id': 4578299, 'author': 'Chris', 'author_id': 307678, 'author_profile': 'https://Stackoverflow.com/users/307678', 'pm_score': 4, 'selected': False, 'text': "<p>If you have lists that are not the same length, you may not want to use zip as per Patricks answer. This works:</p>\n\n<pre><code>&gt;&gt;&gt; zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])\n[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]\n</code></pre>\n\n<p>But with different length lists, zip truncates each item to the length of the shortest list:</p>\n\n<pre><code>&gt;&gt;&gt; zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])\n[('a', 'b', 'c', 'd', 'e')]\n</code></pre>\n\n<p>You can use map with no function to fill empty results with None:</p>\n\n<pre><code>&gt;&gt;&gt; map(None, *[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])\n[('a', 'b', 'c', 'd', 'e'), (1, 2, 3, 4, None)]\n</code></pre>\n\n<p>zip() is marginally faster though.</p>\n"}, {'answer_id': 22115957, 'author': 'wassimans', 'author_id': 313127, 'author_profile': 'https://Stackoverflow.com/users/313127', 'pm_score': 5, 'selected': False, 'text': "<p>I like to use <code>zip(*iterable)</code> (which is the piece of code you're looking for) in my programs as so:</p>\n\n<pre><code>def unzip(iterable):\n    return zip(*iterable)\n</code></pre>\n\n<p>I find <code>unzip</code> more readable.</p>\n"}, {'answer_id': 35012020, 'author': 'G M', 'author_id': 2132157, 'author_profile': 'https://Stackoverflow.com/users/2132157', 'pm_score': 2, 'selected': False, 'text': "<p>It's only another way to do it but it helped me a lot so I write it here:</p>\n\n<p>Having this data structure:</p>\n\n<pre><code>X=[1,2,3,4]\nY=['a','b','c','d']\nXY=zip(X,Y)\n</code></pre>\n\n<p>Resulting in:</p>\n\n<pre><code>In: XY\nOut: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]\n</code></pre>\n\n<p>The more pythonic way to unzip it and go back to the original is this one in my opinion:</p>\n\n<pre><code>x,y=zip(*XY)\n</code></pre>\n\n<p>But this return a tuple so if you need a list you can use:</p>\n\n<pre><code>x,y=(list(x),list(y))\n</code></pre>\n"}, {'answer_id': 35813331, 'author': 'Noyer282', 'author_id': 5918464, 'author_profile': 'https://Stackoverflow.com/users/5918464', 'pm_score': 4, 'selected': False, 'text': "<pre><code>&gt;&gt;&gt; original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]\n&gt;&gt;&gt; tuple([list(tup) for tup in zip(*original)])\n(['a', 'b', 'c', 'd'], [1, 2, 3, 4])\n</code></pre>\n\n<p>Gives a tuple of lists as in the question.</p>\n\n<pre><code>list1, list2 = [list(tup) for tup in zip(*original)]\n</code></pre>\n\n<p>Unpacks the two lists.</p>\n"}, {'answer_id': 50799018, 'author': 'Waylon Flinn', 'author_id': 74291, 'author_profile': 'https://Stackoverflow.com/users/74291', 'pm_score': 1, 'selected': False, 'text': '<p>Since it returns tuples (and can use tons of memory), the <code>zip(*zipped)</code> trick seems more clever than useful, to me.</p>\n\n<p>Here\'s a function that will actually give you the inverse of zip.</p>\n\n<pre><code>def unzip(zipped):\n    """Inverse of built-in zip function.\n    Args:\n        zipped: a list of tuples\n\n    Returns:\n        a tuple of lists\n\n    Example:\n        a = [1, 2, 3]\n        b = [4, 5, 6]\n        zipped = list(zip(a, b))\n\n        assert zipped == [(1, 4), (2, 5), (3, 6)]\n\n        unzipped = unzip(zipped)\n\n        assert unzipped == ([1, 2, 3], [4, 5, 6])\n\n    """\n\n    unzipped = ()\n    if len(zipped) == 0:\n        return unzipped\n\n    dim = len(zipped[0])\n\n    for i in range(dim):\n        unzipped = unzipped + ([tup[i] for tup in zipped], )\n\n    return unzipped\n</code></pre>\n'}, {'answer_id': 51991395, 'author': 'jpp', 'author_id': 9209546, 'author_profile': 'https://Stackoverflow.com/users/9209546', 'pm_score': 2, 'selected': False, 'text': "<p>None of the previous answers <em>efficiently</em> provide the required output, which is a <strong>tuple of lists</strong>, rather than a <em>list of tuples</em>. For the former, you can use <code>tuple</code> with <code>map</code>. Here's the difference:</p>\n\n<pre><code>res1 = list(zip(*original))              # [('a', 'b', 'c', 'd'), (1, 2, 3, 4)]\nres2 = tuple(map(list, zip(*original)))  # (['a', 'b', 'c', 'd'], [1, 2, 3, 4])\n</code></pre>\n\n<p>In addition, most of the previous solutions assume Python 2.7, where <code>zip</code> returns a list rather than an iterator.</p>\n\n<p>For Python 3.x, you will need to pass the result to a function such as <code>list</code> or <code>tuple</code> to exhaust the iterator. For memory-efficient iterators, you can omit the outer <code>list</code> and <code>tuple</code> calls for the respective solutions.</p>\n"}, {'answer_id': 52519708, 'author': 'Charlie Clark', 'author_id': 2385133, 'author_profile': 'https://Stackoverflow.com/users/2385133', 'pm_score': 1, 'selected': False, 'text': "<p>While <code>zip(*seq)</code> is very useful, it may be unsuitable for very long sequences as it will create a tuple of values to be passed in. For example, I've been working with a coordinate system with over a million entries and find it signifcantly faster to create the sequences directly. </p>\n\n<p>A generic approach would be something like this:</p>\n\n<pre><code>from collections import deque\nseq = ((a1, b1, …), (a2, b2, …), …)\nwidth = len(seq[0])\noutput = [deque(len(seq))] * width # preallocate memory\nfor element in seq:\n    for s, item in zip(output, element):\n        s.append(item)\n</code></pre>\n\n<p>But, depending on what you want to do with the result, the choice of collection can make a big difference. In my actual use case, using sets and no internal loop, is noticeably faster than all other approaches.</p>\n\n<p>And, as others have noted, if you are doing this with datasets, it might make sense to use Numpy or Pandas collections instead.</p>\n"}, {'answer_id': 53885047, 'author': 'Azat Ibrakov', 'author_id': 5997596, 'author_profile': 'https://Stackoverflow.com/users/5997596', 'pm_score': 3, 'selected': False, 'text': '<h1>Naive approach</h1>\n\n<pre><code>def transpose_finite_iterable(iterable):\n    return zip(*iterable)  # `itertools.izip` for Python 2 users\n</code></pre>\n\n<p>works fine for finite iterable (e.g. sequences like <code>list</code>/<code>tuple</code>/<code>str</code>) of (potentially infinite) iterables which can be illustrated like</p>\n\n<pre><code>| |a_00| |a_10| ... |a_n0| |\n| |a_01| |a_11| ... |a_n1| |\n| |... | |... | ... |... | |\n| |a_0i| |a_1i| ... |a_ni| |\n| |... | |... | ... |... | |\n</code></pre>\n\n<p>where</p>\n\n<ul>\n<li><code>n in ℕ</code>,</li>\n<li><code>a_ij</code> corresponds to <code>j</code>-th element of <code>i</code>-th iterable,</li>\n</ul>\n\n<p>and after applying <code>transpose_finite_iterable</code> we get</p>\n\n<pre><code>| |a_00| |a_01| ... |a_0i| ... |\n| |a_10| |a_11| ... |a_1i| ... |\n| |... | |... | ... |... | ... |\n| |a_n0| |a_n1| ... |a_ni| ... |\n</code></pre>\n\n<p>Python example of such case where <code>a_ij == j</code>, <code>n == 2</code></p>\n\n<pre><code>&gt;&gt;&gt; from itertools import count\n&gt;&gt;&gt; iterable = [count(), count()]\n&gt;&gt;&gt; result = transpose_finite_iterable(iterable)\n&gt;&gt;&gt; next(result)\n(0, 0)\n&gt;&gt;&gt; next(result)\n(1, 1)\n</code></pre>\n\n<p>But we can\'t use <code>transpose_finite_iterable</code> again to return to  structure of original <code>iterable</code> because <code>result</code> is an infinite iterable of finite iterables (<code>tuple</code>s in our case):</p>\n\n<pre><code>&gt;&gt;&gt; transpose_finite_iterable(result)\n... hangs ...\nTraceback (most recent call last):\n  File "...", line 1, in ...\n  File "...", line 2, in transpose_finite_iterable\nMemoryError\n</code></pre>\n\n<p>So how can we deal with this case?</p>\n\n<h1>... and here comes the <code>deque</code></h1>\n\n<p>After we take a look at docs of <a href="https://docs.python.org/library/itertools.html#itertools.tee" rel="noreferrer"><code>itertools.tee</code> function</a>, there is Python recipe that with some modification can help in our case</p>\n\n<pre><code>def transpose_finite_iterables(iterable):\n    iterator = iter(iterable)\n    try:\n        first_elements = next(iterator)\n    except StopIteration:\n        return ()\n    queues = [deque([element])\n              for element in first_elements]\n\n    def coordinate(queue):\n        while True:\n            if not queue:\n                try:\n                    elements = next(iterator)\n                except StopIteration:\n                    return\n                for sub_queue, element in zip(queues, elements):\n                    sub_queue.append(element)\n            yield queue.popleft()\n\n    return tuple(map(coordinate, queues))\n</code></pre>\n\n<p>let\'s check</p>\n\n<pre><code>&gt;&gt;&gt; from itertools import count\n&gt;&gt;&gt; iterable = [count(), count()]\n&gt;&gt;&gt; result = transpose_finite_iterables(transpose_finite_iterable(iterable))\n&gt;&gt;&gt; result\n(&lt;generator object transpose_finite_iterables.&lt;locals&gt;.coordinate at ...&gt;, &lt;generator object transpose_finite_iterables.&lt;locals&gt;.coordinate at ...&gt;)\n&gt;&gt;&gt; next(result[0])\n0\n&gt;&gt;&gt; next(result[0])\n1\n</code></pre>\n\n<h1>Synthesis</h1>\n\n<p>Now we can define general function for working with iterables of iterables ones of which are finite and another ones are potentially infinite using <a href="https://docs.python.org/library/functools.html#functools.singledispatch" rel="noreferrer"><code>functools.singledispatch</code> decorator</a> like</p>\n\n<pre><code>from collections import (abc,\n                         deque)\nfrom functools import singledispatch\n\n\n@singledispatch\ndef transpose(object_):\n    """\n    Transposes given object.\n    """\n    raise TypeError(\'Unsupported object type: {type}.\'\n                    .format(type=type))\n\n\n@transpose.register(abc.Iterable)\ndef transpose_finite_iterables(object_):\n    """\n    Transposes given iterable of finite iterables.\n    """\n    iterator = iter(object_)\n    try:\n        first_elements = next(iterator)\n    except StopIteration:\n        return ()\n    queues = [deque([element])\n              for element in first_elements]\n\n    def coordinate(queue):\n        while True:\n            if not queue:\n                try:\n                    elements = next(iterator)\n                except StopIteration:\n                    return\n                for sub_queue, element in zip(queues, elements):\n                    sub_queue.append(element)\n            yield queue.popleft()\n\n    return tuple(map(coordinate, queues))\n\n\ndef transpose_finite_iterable(object_):\n    """\n    Transposes given finite iterable of iterables.\n    """\n    yield from zip(*object_)\n\ntry:\n    transpose.register(abc.Collection, transpose_finite_iterable)\nexcept AttributeError:\n    # Python3.5-\n    transpose.register(abc.Mapping, transpose_finite_iterable)\n    transpose.register(abc.Sequence, transpose_finite_iterable)\n    transpose.register(abc.Set, transpose_finite_iterable)\n</code></pre>\n\n<p>which can be considered as its own inverse (mathematicians call this kind of functions <a href="https://en.wikipedia.org/wiki/Involution_(mathematics)" rel="noreferrer">"involutions"</a>) in class of binary operators over finite non-empty iterables.</p>\n\n<hr>\n\n<p>As a bonus of <code>singledispatch</code>ing we can handle <code>numpy</code> arrays like</p>\n\n<pre><code>import numpy as np\n...\ntranspose.register(np.ndarray, np.transpose)\n</code></pre>\n\n<p>and then use it like</p>\n\n<pre><code>&gt;&gt;&gt; array = np.arange(4).reshape((2,2))\n&gt;&gt;&gt; array\narray([[0, 1],\n       [2, 3]])\n&gt;&gt;&gt; transpose(array)\narray([[0, 2],\n       [1, 3]])\n</code></pre>\n\n<h1>Note</h1>\n\n<p>Since <code>transpose</code> returns iterators and if someone wants to have a <code>tuple</code> of <code>list</code>s like in OP -- this can be made additionally with <a href="https://docs.python.org/library/functions.html#map" rel="noreferrer"><code>map</code> built-in function</a> like</p>\n\n<pre><code>&gt;&gt;&gt; original = [(\'a\', 1), (\'b\', 2), (\'c\', 3), (\'d\', 4)]\n&gt;&gt;&gt; tuple(map(list, transpose(original)))\n([\'a\', \'b\', \'c\', \'d\'], [1, 2, 3, 4])\n</code></pre>\n\n<hr>\n\n<h1>Advertisement</h1>\n\n<p>I\'ve added generalized solution to <a href="https://pypi.org/project/lz/" rel="noreferrer"><code>lz</code> package</a> from <code>0.5.0</code> version which can be used like</p>\n\n<pre><code>&gt;&gt;&gt; from lz.transposition import transpose\n&gt;&gt;&gt; list(map(tuple, transpose(zip(range(10), range(10, 20)))))\n[(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), (10, 11, 12, 13, 14, 15, 16, 17, 18, 19)]\n</code></pre>\n\n<hr>\n\n<h1>P.S.</h1>\n\n<p>There is no solution (at least obvious) for handling potentially infinite iterable of potentially infinite iterables, but this case is less common though.</p>\n'}, {'answer_id': 54013413, 'author': 'Neil G', 'author_id': 99989, 'author_profile': 'https://Stackoverflow.com/users/99989', 'pm_score': 2, 'selected': False, 'text': '<p>Consider using <a href="https://more-itertools.readthedocs.io/en/latest/api.html#more_itertools.unzip" rel="nofollow noreferrer">more_itertools.unzip</a>:</p>\n\n<pre><code>&gt;&gt;&gt; from more_itertools import unzip\n&gt;&gt;&gt; original = [(\'a\', 1), (\'b\', 2), (\'c\', 3), (\'d\', 4)]\n&gt;&gt;&gt; [list(x) for x in unzip(original)]\n[[\'a\', \'b\', \'c\', \'d\'], [1, 2, 3, 4]]     \n</code></pre>\n'}, {'answer_id': 61685860, 'author': 'Trasp', 'author_id': 1388027, 'author_profile': 'https://Stackoverflow.com/users/1388027', 'pm_score': 2, 'selected': False, 'text': '<p>While numpy arrays and pandas may be preferrable, this function imitates the behavior of <code>zip(*args)</code> when called as <code>unzip(args)</code>.</p>\n\n<p>Allows for generators, like the result from <code>zip</code> in Python 3, to be passed as <code>args</code> as it iterates through values.</p>\n\n<pre class="lang-py prettyprint-override"><code>def unzip(items, cls=list, ocls=tuple):\n    """Zip function in reverse.\n\n    :param items: Zipped-like iterable.\n    :type  items: iterable\n\n    :param cls: Container factory. Callable that returns iterable containers,\n        with a callable append attribute, to store the unzipped items. Defaults\n        to ``list``.\n    :type  cls: callable, optional\n\n    :param ocls: Outer container factory. Callable that returns iterable\n        containers. with a callable append attribute, to store the inner\n        containers (see ``cls``). Defaults to ``tuple``.\n    :type  ocls: callable, optional\n\n    :returns: Unzipped items in instances returned from ``cls``, in an instance\n        returned from ``ocls``.\n    """\n    # iter() will return the same iterator passed to it whenever possible.\n    items = iter(items)\n\n    try:\n        i = next(items)\n    except StopIteration:\n        return ocls()\n\n    unzipped = ocls(cls([v]) for v in i)\n\n    for i in items:\n        for c, v in zip(unzipped, i):\n            c.append(v)\n\n    return unzipped\n</code></pre>\n\n<p>To use list cointainers, simply run <code>unzip(zipped)</code>, as</p>\n\n<pre class="lang-py prettyprint-override"><code>unzip(zip(["a","b","c"],[1,2,3])) == (["a","b","c"],[1,2,3])\n</code></pre>\n\n<p>To use deques, or other any container sporting <code>append</code>, pass a factory function.</p>\n\n<pre class="lang-py prettyprint-override"><code>from collections import deque\n\nunzip([("a",1),("b",2)], deque, list) == [deque(["a","b"]),deque([1,2])]\n</code></pre>\n\n<p>(Decorate <code>cls</code> and/or <code>main_cls</code> to micro manage container initialization, as briefly shown in the final assert statement above.)</p>\n'}, {'answer_id': 71385682, 'author': 'mkearney', 'author_id': 5435428, 'author_profile': 'https://Stackoverflow.com/users/5435428', 'pm_score': 0, 'selected': False, 'text': '<p>Here\'s a simple one-line answer that produces the desired output:</p>\n<pre class="lang-py prettyprint-override"><code>original = [(\'a\', 1), (\'b\', 2), (\'c\', 3), (\'d\', 4)]\nlist(zip(*original))\n# [(\'a\', \'b\', \'c\', \'d\'), (1, 2, 3, 4)]\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/19339', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/680/']