python सूचियों की सूची से एक फ्लैट सूची कैसे बनाएं?



15 Answers

आप itertools.chain() उपयोग कर सकते हैं:

>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain(*list2d))

या, पायथन> = 2.6 पर, itertools.chain.from_iterable() उपयोग करें, जिसमें सूची को itertools.chain.from_iterable() आवश्यकता नहीं है:

>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain.from_iterable(list2d))

यह दृष्टिकोण तर्कसंगत रूप से अधिक पठनीय है [item for sublist in l for item in sublist] और यह भी तेज़ प्रतीत होता है:

[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;import itertools' 'list(itertools.chain.from_iterable(l))'
10000 loops, best of 3: 24.2 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 45.2 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 488 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 522 usec per loop
[me@home]$ python --version
Python 2.7.3
python list multidimensional-array flatten

मुझे आश्चर्य है कि पाइथन में सूचियों की सूची से एक साधारण सूची बनाने के लिए शॉर्टकट है या नहीं।

मैं इसे लूप में कर सकता हूं, लेकिन हो सकता है कि कुछ ठंडा "एक-लाइनर" हो? मैंने इसे कम करने की कोशिश की, लेकिन मुझे एक त्रुटि मिली।

कोड

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
reduce(lambda x, y: x.extend(y), l)

त्रुटि संदेश

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'



मैंने perfplot (मेरा पालतू जानवर प्रोजेक्ट, अनिवार्य रूप से समय-समय पर एक रैपर) के साथ सबसे अधिक सुझाए गए समाधानों का परीक्षण किया, और पाया

list(itertools.chain.from_iterable(a))

सबसे तेज़ समाधान होने के लिए (यदि 10 से अधिक सूचियों को समेकित किया गया है)।

साजिश को पुन: उत्पन्न करने के लिए कोड:

import functools
import itertools
import numpy
import operator
import perfplot


def forfor(a):
    return [item for sublist in a for item in sublist]


def sum_brackets(a):
    return sum(a, [])


def functools_reduce(a):
    return functools.reduce(operator.concat, a)


def itertools_chain(a):
    return list(itertools.chain.from_iterable(a))


def numpy_flat(a):
    return list(numpy.array(a).flat)


def numpy_concatenate(a):
    return list(numpy.concatenate(a))


perfplot.show(
    setup=lambda n: [list(range(10))] * n,
    kernels=[
        forfor, sum_brackets, functools_reduce, itertools_chain, numpy_flat,
        numpy_concatenate
        ],
    n_range=[2**k for k in range(16)],
    logx=True,
    logy=True,
    xlabel='num lists'
    )



यहां एक सामान्य दृष्टिकोण है जो संख्याओं , तारों , नेस्टेड सूचियों और मिश्रित कंटेनर पर लागू होता है।

कोड

from collections import Iterable


def flatten(items):
    """Yield items from any nested iterable; see Reference."""
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            for sub_x in flatten(x):
                yield sub_x
        else:
            yield x

नोट: पायथन 3 में, for sub_x in flatten(x): yield sub_x प्रतिस्थापित कर सकते हैं for sub_x in flatten(x): yield sub_x

डेमो

lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(flatten(lst))                                         # nested lists
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

mixed = [[1, [2]], (3, 4, {5, 6}, 7), 8, "9"]              # numbers, strs, nested & mixed
list(flatten(mixed))
# [1, 2, 3, 4, 5, 6, 7, 8, '9']

संदर्भ

  • यह समाधान बेज़ले, डी और बी जोन्स में एक नुस्खा से संशोधित किया गया है पकाने की विधि 4.14, पायथन कुकबुक तीसरी एड।, ओ रेली मीडिया इंक सेबस्तोपोल, सीए: 2013।
  • पहले एसओ पोस्ट , संभवतः मूल प्रदर्शन मिला।



आप विस्तार का उपयोग क्यों करते हैं?

reduce(lambda x, y: x+y, l)

यह ठीक काम करना चाहिए।




ऑपरेटर.एड के साथ भ्रम प्रतीत होता है! जब आप एक साथ दो सूचियां जोड़ते हैं, तो इसके लिए सही शब्द concat , जोड़ नहीं है। operator.concat वह है जिसे आपको उपयोग करने की आवश्यकता है।

यदि आप कार्यात्मक सोच रहे हैं, तो यह उतना ही आसान है जितना ::

>>> list2d = ((1, 2, 3), (4, 5, 6), (7,), (8, 9))
>>> reduce(operator.concat, list2d)
(1, 2, 3, 4, 5, 6, 7, 8, 9)

आप देखते हैं कि अनुक्रम प्रकार का सम्मान कम हो जाता है, इसलिए जब आप एक ट्यूपल की आपूर्ति करते हैं, तो आप एक ट्यूपल वापस लेते हैं। चलो एक सूची के साथ प्रयास करें ::

>>> list2d = [[1, 2, 3],[4, 5, 6], [7], [8, 9]]
>>> reduce(operator.concat, list2d)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

आह, आप एक सूची वापस आते हैं।

प्रदर्शन के बारे में कैसे ::

>>> list2d = [[1, 2, 3],[4, 5, 6], [7], [8, 9]]
>>> %timeit list(itertools.chain.from_iterable(list2d))
1000000 loops, best of 3: 1.36 µs per loop

से_iterable बहुत तेज़ है! लेकिन यह concat के साथ कम करने के लिए कोई तुलना नहीं है।

>>> list2d = ((1, 2, 3),(4, 5, 6), (7,), (8, 9))
>>> %timeit reduce(operator.concat, list2d)
1000000 loops, best of 3: 492 ns per loop



more_itertools पैकेज को स्थापित करने पर विचार करें।

> pip install more_itertools

यह flatten के लिए एक कार्यान्वयन के साथ जहाज ( source , itertools व्यंजनों से ):

import more_itertools


lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.flatten(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

संस्करण 2.4 के अनुसार, आप अधिक जटिल, नेस्टेड पुनरावृत्तियों को more_itertools.collapse ( source , abarnet द्वारा योगदान) के साथ more_itertools.collapse कर सकते हैं।

lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.collapse(lst)) 
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

lst = [[1, 2, 3], [[4, 5, 6]], [[[7]]], 8, 9]              # complex nesting
list(more_itertools.collapse(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]



def flatten(l, a):
    for i in l:
        if isinstance(i, list):
            flatten(i, a)
        else:
            a.append(i)
    return a

print(flatten([[[1, [1,1, [3, [4,5,]]]], 2, 3], [4, 5],6], []))

# [1, 1, 1, 3, 4, 5, 2, 3, 4, 5, 6]



कोई भी न्यूपी के flat का उपयोग कर सकता है:

import numpy as np
list(np.array(l).flat)

11/02/2016 संपादित करें: केवल तभी काम करता है जब उपन्यासकारों के समान आयाम होते हैं।




underscore.py पैकेज प्रशंसक के लिए सरल कोड

from underscore import _
_.flatten([[1, 2, 3], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

यह सभी flatten समस्याओं को हल करता है (कोई भी सूची आइटम या जटिल घोंसले)

from underscore import _
# 1 is none list item
# [2, [3]] is complex nesting
_.flatten([1, [2, [3]], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

आप पीपी के साथ underscore.py स्थापित कर सकते हैं

pip install underscore.py



परिवर्तनीय लंबाई की पाठ-आधारित सूचियों से निपटने के दौरान स्वीकृत उत्तर मेरे लिए काम नहीं करता था। यहां एक वैकल्पिक दृष्टिकोण है जो मेरे लिए काम करता है।

l = ['aaa', 'bb', 'cccccc', ['xx', 'yyyyyyy']]

स्वीकृत उत्तर जो काम नहीं करता है:

flat_list = [item for sublist in l for item in sublist]
print(flat_list)
['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'c', 'c', 'c', 'xx', 'yyyyyyy']

नए प्रस्तावित समाधान है कि किया था मेरे लिए काम:

flat_list = []
_ = [flat_list.extend(item) if isinstance(item, list) else flat_list.append(item) for item in l if item]
print(flat_list)
['aaa', 'bb', 'cccccc', 'xx', 'yyyyyyy']



यदि आप क्लीनर लुक के लिए थोड़ी सी मात्रा छोड़ने को तैयार हैं, तो आप इसका उपयोग कर सकते हैं numpy.concatenate().tolist()या numpy.concatenate().ravel().tolist():

import numpy

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]] * 99

%timeit numpy.concatenate(l).ravel().tolist()
1000 loops, best of 3: 313 µs per loop

%timeit numpy.concatenate(l).tolist()
1000 loops, best of 3: 312 µs per loop

%timeit [item for sublist in l for item in sublist]
1000 loops, best of 3: 31.5 µs per loop

आप docs numpy.concatenate और numpy.ravel में यहां और अधिक जानकारी प्राप्त कर सकते हैंnumpy.ravel




एक और असामान्य दृष्टिकोण जो हेटरो- और पूर्णांक की सजातीय सूचियों के लिए काम करता है:

from typing import List


def flatten(l: list) -> List[int]:
    """Flatten an arbitrary deep nested list of lists of integers.

    Examples:
        >>> flatten([1, 2, [1, [10]]])
        [1, 2, 1, 10]

    Args:
        l: Union[l, Union[int, List[int]]

    Returns:
        Flatted list of integer
    """
    return [int(i.strip('[ ]')) for i in str(l).split(',')]



मैं हाल ही में एक ऐसी स्थिति में आया जहां मेरे पास उपन्यासकारों में तारों और संख्यात्मक डेटा का मिश्रण था

test = ['591212948',
['special', 'assoc', 'of', 'Chicago', 'Jon', 'Doe'],
['Jon'],
['Doe'],
['fl'],
92001,
555555555,
'hello',
['hello2', 'a'],
'b',
['hello33', ['z', 'w'], 'b']]

जहां विधियों ने flat_list = [item for sublist in test for item in sublist]काम नहीं किया है। तो, मैं 1+ स्तर के उपन्यासकारों के लिए निम्नलिखित समाधान के साथ आया था

def concatList(data):
    results = []
    for rec in data:
        if type(rec) == list:
            results += rec
            results = concatList(results)
        else:
            results.append(rec)
    return results

और नतीजा

In [38]: concatList(test)
Out[38]:
 Out[60]:
['591212948',
'special',
'assoc',
'of',
'Chicago',
'Jon',
'Doe',
'Jon',
'Doe',
'fl',
92001,
555555555,
'hello',
'hello2',
'a',
'b',
'hello33',
'z',
'w',
'b']



आप वास्तविक स्टैक डेटा संरचना का उपयोग करके स्टैक पर रिकर्सिव कॉल से बच सकते हैं।

alist = [1,[1,2],[1,2,[4,5,6],3, "33"]]
newlist = []

while len(alist) > 0 :
  templist = alist.pop()
  if type(templist) == type(list()) :
    while len(templist) > 0 :
      temp = templist.pop()
      if type(temp) == type(list()) :
        for x in temp :
          templist.append(x)
      else :
        newlist.append(temp)
  else :
    newlist.append(templist)
print(list(reversed(newlist)))



एक साधारण पुनरावर्ती विधि का उपयोग कर reduceसे functoolsऔर addसूचियों पर ऑपरेटर:

>>> from functools import reduce
>>> from operator import add
>>> flatten = lambda lst: [lst] if type(lst) is int else reduce(add, [flatten(ele) for ele in lst])
>>> flatten(l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

समारोह पैरामीटर के रूप flattenमें लेता है lst। यह के सभी तत्वों को लूप lstतक पहुँच रहा पूर्णांकों (भी बदल सकते हैं intकरने के लिए float, strहै, जो सबसे बाहरी प्रत्यावर्तन की वापसी मूल्य को जोड़ रहे हैं अन्य डेटा प्रकार के लिए, आदि)।

forलूप और मोनैड जैसी विधियों के विपरीत , यह एक सामान्य समाधान है जो सूची गहराई से सीमित नहीं है । उदाहरण के लिए, 5 की गहराई वाली एक सूची को उसी तरह से फ़्लैट किया जा सकता है जैसे l:

>>> l2 = [[3, [1, 2], [[[6], 5], 4, 0], 7, [[8]], [9, 10]]]
>>> flatten(l2)
[3, 1, 2, 6, 5, 4, 0, 7, 8, 9, 10]





Related