ট্রান্সপোজ / আনজিপ ফাংশন (জিপের বিপরীত)?


504

আমার কাছে 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])

একটি বিল্টিন ফাংশন আছে যে এটি করে?


6
নীচে দুর্দান্ত উত্তরগুলি, তবে নম্পতির ট্রান্সপোজটিও দেখুন
opyate করুন

3
তালিকার পরিবর্তে জেনারেটরগুলির সাথেও একই কাজ করতে এই সুন্দর উত্তরটি দেখুন: কীভাবে আনজিপ-
অন

উত্তর:


777

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সরাসরি (একটি টুপলে রূপান্তরিত হওয়ার পরে) এ দেওয়া হয়, সুতরাং যুক্তিগুলির সংখ্যা খুব বড় হওয়ার বিষয়ে চিন্তা করার দরকার নেই।


20
ওহ, যদি এটি এত সহজ ছিল। এইভাবে আনজিপিং করা zip([], [])আপনাকে পায় না [], []। এটা আপনাকে পায় []। যদি কেবল ...
ব্যবহারকারী 2357112

4
পাইথন 3 এ কাজ করে না। দেখুন: স্ট্যাকওভারফ্লো.com
টমি

30
@ টমি এটি ভুল। zipপাইথন 3 এ ঠিক একই কাজ করে এটি বাদে এটি তালিকার পরিবর্তে একটি পুনরাবৃত্তি প্রদান করে। উপরের মত একই আউটপুট পেতে আপনার কেবল তালিকায় জিপ কলটি list(zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)]))[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
আবদ্ধ

4
বিজ্ঞপ্তি: আপনি খুব দীর্ঘ তালিকাগুলির সাহায্যে মেমরি এবং পারফরম্যান্সের সমস্যাগুলি পূরণ করতে পারেন।
লরেন্ট LAPORTE

1
@ জনপি: listগুলি ঠিক আছে। কিন্তু আপনি যদি (সকল একবারে পূর্ণ ফলাফলের বুঝতে চেষ্টা listফল ifying zip), আপনি মেমরি অনেক ব্যবহার হতে পারে (কারণ সবtuple গুলি একযোগে তৈরি করা হবে)। আপনি শুধু ফল পুনরুক্তি করতে পারেন zipছাড়া listifying, আপনি মেমরি অনেক সংরক্ষণ করব। কেবলমাত্র অন্য উদ্বেগটি হ'ল যদি ইনপুটটিতে অনেক উপাদান থাকে; সেখানে ব্যয় হচ্ছে এটি অবশ্যই তাদের সকলকে আর্গুমেন্ট হিসাবে আনপ্যাক zipকরবে এবং তাদের সবার জন্য পুনরাবৃত্তি তৈরি এবং সঞ্চয় করতে হবে। এই মাত্র একটি বাস্তব সমস্যা খুব দীর্ঘ listগুলি (উপাদান বা তার বেশি শত সহস্র মনে)।
ShadowRanger

29

আপনি করতে পারেন

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

এটি আরও ভাল স্কেল করা উচিত । বিশেষত পাইথন যদি প্রয়োজন না হয় তবে তালিকার বোধগম্যতা না বাড়িয়ে দেওয়া ভাল।

(ঘটনাক্রমে, এটি তালিকার একটি তালিকার পরিবর্তে তালিকার একটি 2-টিপল (জোড়া) তৈরি zipকরে))

যদি প্রকৃত তালিকার পরিবর্তে জেনারেটরগুলি ঠিক থাকে তবে এটি এটি করবে:

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

আপনি প্রতিটি উপাদান জিজ্ঞাসা না করা পর্যন্ত জেনারেটর তালিকার মধ্য দিয়ে মুখ কাটায় না, তবে অন্যদিকে, তারা মূল তালিকার রেফারেন্স রাখে।


8
"বিশেষত পাইথন যদি প্রয়োজন না হয় তবে তালিকার বোঝাপড়াগুলি বাড়িয়ে না তোলার বিষয়ে ভাল কাজ করে।" মিমি ... সাধারণত, তালিকান বোধগম্যতা অবিলম্বে প্রসারিত হয় - বা আমি কিছু ভুল পেয়েছি?
glglgl

1
@glglgl: না, আপনি সম্ভবত ঠিক বলেছেন। আমি কেবল আশা করছিলাম কিছু ভবিষ্যতের সংস্করণ সঠিক কাজটি শুরু করবে। (এটি পরিবর্তন করা অসম্ভব নয়, পার্শ্ব-প্রতিক্রিয়াশীল শব্দার্থবিজ্ঞানের যে পরিবর্তনের প্রয়োজন সম্ভবত ইতিমধ্যে নিরুৎসাহিত করা হয়েছে।)
অ্যান্ডার্স ইউরেনিয়াস

9
আপনি যা পাওয়ার আশা করছেন তা হ'ল জেনারেটরের এক্সপ্রেশন - যা ইতিমধ্যে বিদ্যমান।
glglgl

12
এটি zip(*x)সংস্করণের চেয়ে 'স্কেল ভাল' করে না । zip(*x)লুপটি কেবল একটি পাসের প্রয়োজন, এবং স্ট্যাক উপাদান ব্যবহার করে না।
habnabit

1
এটি "আরও ভাল স্কেল করে" বা স্থানান্তরিত তথ্যের তুলনায় মূল ডেটার জীবনচক্রের উপর নির্ভর করে না। এই উত্তরটি ব্যবহারের চেয়ে কেবলমাত্র উত্তমরূপে zipযদি ব্যবহার-কেসটি হ'ল ট্রান্সপোজড ডেটা ব্যবহার করা হয় এবং তাত্ক্ষণিকভাবে ফেলে দেওয়া হয়, তবে মূল তালিকাগুলি মেমরিতে আরও বেশি সময় ধরে থাকে।
ইকভু

21

যদি আপনার তালিকাগুলি একই দৈর্ঘ্য নয় তবে প্যাট্রিক্সের উত্তর অনুসারে আপনি জিপটি ব্যবহার করতে নাও চান। এইটা কাজ করে:

>>> 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)]

জিপ () যদিও সামান্য দ্রুত।


4
আপনিও ব্যবহার করতে পারেনizip_longest
মার্সিন

3
zip_longestপাইথন 3 ব্যবহারকারী হিসাবে পরিচিত ।
zizollo

1
@ গ্রিজেশচৌহান আমি জানি এটি সত্যিই পুরানো, তবে এটি বৈশিষ্ট্যে নির্মিত একটি অদ্ভুত: ডকস.পিথথন.আর / 2 / লিবারি / ফাংশনস html#map "যদি ফাংশনটি কিছু না হয় তবে পরিচয় ফাংশনটি ধরে নেওয়া হয়; যদি একাধিক যুক্তি থাকে, মানচিত্র () সমস্ত পুনরাবৃত্ত (এক ধরণের ট্রান্সপোজ অপারেশন) থেকে সম্পর্কিত আইটেমযুক্ত টিপলস সমন্বিত একটি তালিকা ফেরত দেয় The
ক্যাকটাস 1

18

আমি zip(*iterable)আমার প্রোগ্রামগুলিতে যেমনটি ব্যবহার করতে চাই (যা আপনি অনুসন্ধান করছেন সেটির টুকরো):

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

আমি unzipআরও পাঠযোগ্য।


12
>>> 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])

প্রশ্নের মতো তালিকাগুলি দেয় up

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

দুটি তালিকা আনপ্যাক করে।


8

নিষ্পাপ পদ্ধতির

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

(সম্ভাব্য অসীম) পুনরাবৃত্তের সীমাবদ্ধ পুনরাবৃত্তিযোগ্য (যেমন list/ tuple/ str) এর মতো ক্রমগুলির জন্য সূক্ষ্মভাবে কাজ করে যা চিত্রিত করা যেতে পারে

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

কোথায়

  • n in ℕ,
  • a_ijসাথে সঙ্গতিপূর্ণ jএর -th উপাদান i-th iterable,

এবং প্রয়োগের পরে transpose_finite_iterableআমরা পেতে

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

পাইথনের যেমন উদাহরণের উদাহরণ যেখানে 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সীমাবদ্ধ পুনরাবৃত্তির ( tupleআমাদের ক্ষেত্রে) অসীম পুনরাবৃত্তিযোগ্য :

>>> 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ফাংশনের ডক্সগুলি একবার দেখার পরে , পাইথন রেসিপি রয়েছে যা কিছু সংশোধন করে আমাদের ক্ষেত্রে সহায়তা করতে পারে

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)

সীমাবদ্ধ নন-খালি পুনরাবৃত্তির তুলনায় বাইনারি অপারেটরগুলির শ্রেণিতে এটি গণিতবিদগণ তার নিজস্ব বিপরীতমুখী হিসাবে গণ্য (গণিতবিদরা এই ধরণের ফাংশনগুলিকে "অন্তর্ভুক্তি" বলে ) মনে করেন।


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এর listওপি মত গুলি - এই সঙ্গে অতিরিক্ত তৈরি করা যেতে পারে 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)]

পুনশ্চ

সম্ভাব্য অসীম পুনরাবৃত্তির সম্ভাব্য অসীম পুনরাবৃত্তিকে পরিচালনা করার জন্য কোনও সমাধান নেই (অন্তত সুস্পষ্ট) তবে এই ক্ষেত্রে যদিও কম দেখা যায় না।


4

এটি করার অন্য একটি উপায় তবে এটি আমাকে অনেক সহায়তা করেছিল তাই আমি এটি এখানে লিখছি:

এই ডেটা কাঠামোটি রয়েছে:

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')]

এটিকে আনজিপ করে এবং মূলটিতে ফিরে যাওয়ার আরও অজগর উপায়টি আমার মতে এটি:

x,y=zip(*XY)

তবে এটি একটি টিপল ফেরত দেয় তাই আপনার যদি কোনও তালিকার প্রয়োজন হয় তবে আপনি ব্যবহার করতে পারেন:

x,y=(list(x),list(y))


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

ধারাবাহিকভাবে টিপলস পুনরুদ্ধার করা আমার পক্ষে তেমন দক্ষ বলে মনে হয় না তবে আপনি স্মৃতিশক্তি রোধ করতে পারে এমন ডিক্স ব্যবহার করে এই পদ্ধতির প্রসার ঘটাতে পারেন।
চার্লি ক্লার্ক

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])

এছাড়াও, পূর্ববর্তী সমাধানগুলির বেশিরভাগটি পাইথন ২.7 ধরে থাকে, যেখানে zipপুনরাবৃত্তির পরিবর্তে একটি তালিকা দেয়।

পাইথন ৩.x এর জন্য আপনাকে ফলাফলটি কোনও ফাংশনে যেমন পাস করতে হবে listবা tupleপুনরাবৃত্তকারীকে ক্লান্ত করতে হবে। মেমরি দক্ষ দক্ষ পুনরাবৃত্তির জন্য, আপনি বাইরেরটিকে বাদ দিতে পারেন listএবং tupleসংশ্লিষ্ট সমাধানের জন্য কল করতে পারেন ।


0

যদিও zip(*seq) এটি খুব কার্যকর, এটি খুব দীর্ঘ ক্রমগুলির জন্য অনুপযুক্ত হতে পারে কারণ এটি পাস করার জন্য একটি মানকে দ্বিগুণ করে তোলে example উদাহরণস্বরূপ, আমি এক মিলিয়ন এরও বেশি একটি সমন্বিত সিস্টেমের সাথে কাজ করছি এবং এটি তৈরির লক্ষণীয়ভাবে দ্রুত খুঁজে পেয়েছি ক্রম সরাসরি।

একটি জেনেরিক পদ্ধতির কিছু হবে:

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)

তবে, ফলাফলটির সাথে আপনি কী করতে চান তার উপর নির্ভর করে সংগ্রহের পছন্দটি একটি বড় পার্থক্য আনতে পারে। আমার প্রকৃত ব্যবহারের ক্ষেত্রে, সেটগুলি ব্যবহার করে এবং কোনও অভ্যন্তরীণ লুপ ব্যবহার করা অন্য সমস্ত পদ্ধতির চেয়ে লক্ষণীয়ভাবে দ্রুত।

এবং অন্যরা যেমন উল্লেখ করেছে, আপনি যদি এটি ডেটাসেট দিয়ে করছেন, তবে এটির পরিবর্তে নম্পি বা পান্ডাস সংগ্রহগুলি ব্যবহার করা বুদ্ধিমান হতে পারে।


0

যদিও নাম্পার অ্যারে এবং পান্ডা পছন্দসই হতে পারে তবে এই ফাংশনটি zip(*args)যখন ডাকা হয় তার আচরণের অনুকরণ করে unzip(args)

জেনারেটরগুলির argsমানগুলির মাধ্যমে যেমন এটি পুনরাবৃত্তি হয় তেমনি পাস করার অনুমতি দেয় । মাইক্রো ম্যানেজার ধারক আরম্ভের সাজাইয়া clsএবং / অথবা main_cls

def unzip(items, cls=list, main_cls=tuple):
    """Zip function in reverse.

    :param items: Zipped-like iterable.
    :type  items: iterable

    :param cls: Callable that returns iterable with callable append attribute.
        Defaults to `list`.
    :type  cls: callable, optional

    :param main_cls: Callable that returns iterable with callable append
        attribute. Defaults to `tuple`.
    :type  main_cls: callable, optional

    :returns: Unzipped items in instances returned from `cls`, in an instance
        returned from `main_cls`.

    :Example:

        assert unzip(zip(["a","b","c"],[1,2,3])) == (["a","b",c"],[1,2,3])
        assert unzip([("a",1),("b",2),("c",3)]) == (["a","b","c"],[1,2,3])
        assert unzip([("a",1)], deque, list) == [deque(["a"]),deque([1])]
        assert unzip((["a"],["b"]), lambda i: deque(i,1)) == (deque(["b"]),)
    """
    items = iter(items)

    try:
        i = next(items)
    except StopIteration:
        return main_cls()

    unzipped = main_cls(cls([v]) for v in i)

    for i in items:
        for c,v in zip(unzipped,i):
            c.append(v)

    return unzipped
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.