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




list multidimensional-array (20)

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

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

कोड

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'

https://code.i-harness.com


आप 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] और यह भी तेज़ प्रतीत होता है:

[[email protected]]$ 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
[[email protected]]$ 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
[[email protected]]$ 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
[[email protected]]$ 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
[[email protected]]$ python --version
Python 2.7.3

आप numpy का उपयोग कर सकते हैं:
flat_list = list(np.concatenate(list_of_list))


ऊपर अनिल के फ़ंक्शन की एक खराब विशेषता यह है कि उपयोगकर्ता को खाली सूची [] लिए मैन्युअल रूप से दूसरे तर्क को मैन्युअल रूप से निर्दिष्ट करने की आवश्यकता होती है। यह बदले में एक डिफ़ॉल्ट होना चाहिए। पाइथन ऑब्जेक्ट्स काम करने के तरीके के कारण, इन्हें फ़ंक्शन के अंदर सेट किया जाना चाहिए, न कि तर्कों में।

यहां एक कार्यशील कार्य है:

def list_flatten(l, a=None):
    #check a
    if a is None:
        #initialize with empty list
        a = []

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

परिक्षण:

In [2]: lst = [1, 2, [3], [[4]],[5,[6]]]

In [3]: lst
Out[3]: [1, 2, [3], [[4]], [5, [6]]]

In [11]: list_flatten(lst)
Out[11]: [1, 2, 3, 4, 5, 6]

ऑपरेटर.एड के साथ भ्रम प्रतीत होता है! जब आप एक साथ दो सूचियां जोड़ते हैं, तो इसके लिए सही शब्द 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

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

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

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


मेरे लिए सबसे सरल लग रहा है:

>>> import numpy as np
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> print (np.concatenate(l))
[1 2 3 4 5 6 7 8 9]

यदि आप डेटा-स्ट्रक्चर को फ़्लैट करना चाहते हैं, जहां आप नहीं जानते कि यह कितना गहरा है, तो आप iteration_utilities.deepflatten 1 का उपयोग कर सकते हैं

>>> from iteration_utilities import deepflatten

>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(deepflatten(l, depth=1))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> l = [[1, 2, 3], [4, [5, 6]], 7, [8, 9]]
>>> list(deepflatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

यह जनरेटर है इसलिए आपको परिणाम को एक list डालना होगा या स्पष्ट रूप से इसे फिर से चालू करना होगा।

केवल एक स्तर को फ़्लैट करने के लिए और यदि प्रत्येक आइटम स्वयं ही itertools.chain.from_iterable : itertools.chain.from_iterable तो आप iteration_utilities.flatten भी उपयोग कर सकते हैं जो itertools.chain.from_iterable आस-पास केवल एक पतली आवरण है:

>>> from iteration_utilities import flatten
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(flatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

बस कुछ समय जोड़ने के लिए (निको श्लोमर उत्तर के आधार पर जिसमें इस उत्तर में प्रस्तुत समारोह शामिल नहीं था):

यह स्पैन किए गए मूल्यों की विशाल श्रृंखला के लिए समायोजित करने के लिए लॉग-लॉग प्लॉट है। गुणात्मक तर्क के लिए: निचला बेहतर है।

परिणाम दिखाते हैं कि यदि पुनरावर्तनीय में केवल कुछ आंतरिक पुनरावृत्तियों होते हैं तो sum सबसे तेज़ होगा, हालांकि लंबे समय तक केवल itertools.chain.from_iterable , iteration_utilities.deepflatten या नेस्टेड समझ के साथ itertools.chain.from_iterable साथ उचित प्रदर्शन होता है (जैसा कि पहले से निको श्लोमर द्वारा देखा गया है)।

from itertools import chain
from functools import reduce
from collections import Iterable  # or from collections.abc import Iterable
import operator
from iteration_utilities import deepflatten

def nested_list_comprehension(lsts):
    return [item for sublist in lsts for item in sublist]

def itertools_chain_from_iterable(lsts):
    return list(chain.from_iterable(lsts))

def pythons_sum(lsts):
    return sum(lsts, [])

def reduce_add(lsts):
    return reduce(lambda x, y: x + y, lsts)

def pylangs_flatten(lsts):
    return list(flatten(lsts))

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

def reduce_concat(lsts):
    return reduce(operator.concat, lsts)

def iteration_utilities_deepflatten(lsts):
    return list(deepflatten(lsts, depth=1))


from simple_benchmark import benchmark

b = benchmark(
    [nested_list_comprehension, itertools_chain_from_iterable, pythons_sum, reduce_add,
     pylangs_flatten, reduce_concat, iteration_utilities_deepflatten],
    arguments={2**i: [[0]*5]*(2**i) for i in range(1, 13)},
    argument_name='number of inner lists'
)

b.plot()

1 अस्वीकरण: मैं उस पुस्तकालय का लेखक हूं


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

कोड

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।
  • पहले एसओ पोस्ट , संभवतः मूल प्रदर्शन मिला।

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

matplotlib.cbook.flatten() नेस्टेड सूचियों के लिए काम करेगा भले ही वे उदाहरण से अधिक गहराई से घोंसले हों।

import matplotlib
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
print(list(matplotlib.cbook.flatten(l)))
l2 = [[1, 2, 3], [4, 5, 6], [7], [8, [9, 10, [11, 12, [13]]]]]
print list(matplotlib.cbook.flatten(l2))

परिणाम:

[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

अंडरस्कोर से यह 18x तेज है। _। Flatten:

Average time over 1000 trials of matplotlib.cbook.flatten: 2.55e-05 sec
Average time over 1000 trials of underscore._.flatten: 4.63e-04 sec
(time for underscore._)/(time for matplotlib.cbook) = 18.1233394636

मैं अपना बयान वापस लेता हूं। योग विजेता नहीं है। हालांकि सूची तेज होने पर यह तेज़ है। लेकिन प्रदर्शन बड़ी सूचियों के साथ महत्वपूर्ण रूप से घटता है।

>>> timeit.Timer(
        '[item for sublist in l for item in sublist]',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10000'
    ).timeit(100)
2.0440959930419922

योग संस्करण अभी भी एक मिनट से अधिक समय तक चल रहा है और अभी तक प्रसंस्करण नहीं किया है!

मध्यम सूचियों के लिए:

>>> timeit.Timer(
        '[item for sublist in l for item in sublist]',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
    ).timeit()
20.126545906066895
>>> timeit.Timer(
        'reduce(lambda x,y: x+y,l)',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
    ).timeit()
22.242258071899414
>>> timeit.Timer(
        'sum(l, [])',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
    ).timeit()
16.449732065200806

छोटी सूचियों और समय सारिणी का उपयोग करना: संख्या = 1000000

>>> timeit.Timer(
        '[item for sublist in l for item in sublist]',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
    ).timeit()
2.4598159790039062
>>> timeit.Timer(
        'reduce(lambda x,y: x+y,l)',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
    ).timeit()
1.5289170742034912
>>> timeit.Timer(
        'sum(l, [])',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
    ).timeit()
1.0598428249359131

लेखक से नोट : यह अक्षम है। लेकिन मजेदार, क्योंकि monads भयानक हैं। यह उत्पादन पायथन कोड के लिए उपयुक्त नहीं है।

>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]

यह केवल पहले तर्क में पारित होने वाले पुनरावृत्तियों के तत्वों को बताता है, दूसरे तर्क को योग के प्रारंभिक मूल्य के रूप में मानते हैं (यदि नहीं दिया गया है, तो 0 का उपयोग किया जाता है और यह मामला आपको एक त्रुटि देगा)।

चूंकि आप नेस्टेड सूचियों को sum([[1,3],[2,4]],[]) रहे हैं, तो आपको वास्तव में sum([[1,3],[2,4]],[]) परिणामस्वरूप [1,3]+[2,4] मिलती है, जो [1,3,2,4]

ध्यान दें कि केवल सूचियों की सूचियों पर काम करता है। सूचियों की सूचियों की सूचियों के लिए, आपको एक और समाधान की आवश्यकता होगी।


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

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

एक साधारण पुनरावर्ती विधि का उपयोग कर 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]

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

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

यह सबसे प्रभावी तरीका नहीं हो सकता है लेकिन मैंने एक लाइनर (वास्तव में एक दो-लाइनर) डालने का विचार किया। दोनों संस्करण मनमाने ढंग से पदानुक्रम नेस्टेड सूचियों पर काम करेंगे, और भाषा सुविधाओं (पायथन 3.5) और रिकर्सन का शोषण करेंगे।

def make_list_flat (l):
    flist = []
    flist.extend ([l]) if (type (l) is not list) else [flist.extend (make_list_flat (e)) for e in l]
    return flist

a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = make_list_flat(a)
print (flist)

आउटपुट है

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

यह पहली बार गहराई में काम करता है। रिकर्सन तब तक नीचे चला जाता है जब तक कि यह एक गैर-सूची तत्व नहीं पाता है, फिर स्थानीय चर को बढ़ाता है flistऔर उसके बाद इसे माता-पिता को वापस ले जाता है। जब भी flistवापस आ जाता है, तो यह माता-पिता की flistसूची समझ में बढ़ाया जाता है । इसलिए, जड़ पर, एक फ्लैट सूची लौटा दी जाती है।

उपरोक्त एक कई स्थानीय सूचियां बनाता है और उन्हें वापस देता है जिनका उपयोग माता-पिता की सूची को बढ़ाने के लिए किया जाता है। मुझे लगता है कि इसके लिए रास्ता flistनीचे की तरह एक ग्लोबल बना सकता है ।

a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = []
def make_list_flat (l):
    flist.extend ([l]) if (type (l) is not list) else [make_list_flat (e) for e in l]

make_list_flat(a)
print (flist)

आउटपुट फिर से है

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

हालांकि मैं इस समय दक्षता के बारे में निश्चित नहीं हूं।


def flatten(alist):
    if alist == []:
        return []
    elif type(alist) is not list:
        return [alist]
    else:
        return flatten(alist[0]) + flatten(alist[1:])

flat_list = []
for i in list_of_list:
    flat_list+=i

यह कोड ठीक काम करता है क्योंकि यह सिर्फ सूची को विस्तारित करता है। हालांकि यह बहुत समान है लेकिन केवल लूप के लिए एक है। इसलिए लूप के लिए 2 जोड़ने की तुलना में इसकी जटिलता कम है।


flat_list = [item for sublist in l for item in sublist]

जिसका मतलब है:

for sublist in l:
    for item in sublist:
        flat_list.append(item)

अभी तक पोस्ट शॉर्टकट से तेज है। ( l flatten की सूची है।)

यहां एक संबंधित कार्य है:

flatten = lambda l: [item for sublist in l for item in sublist]

सबूत के लिए, हमेशा के रूप में, आप मानक पुस्तकालय में timeit मॉड्यूल का उपयोग कर सकते हैं:

$ 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: 143 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 969 usec per loop
$ 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: 1.1 msec per loop

स्पष्टीकरण: + पर आधारित शॉर्टकट्स ( sum में अंतर्निहित उपयोग सहित) आवश्यक हैं, O(L**2) जब एल sublists हैं - मध्यवर्ती परिणाम सूची लंबी हो रही है, प्रत्येक चरण पर एक नया मध्यवर्ती परिणाम सूची वस्तु आवंटित की जाती है, और पिछले मध्यवर्ती परिणाम में सभी वस्तुओं की प्रतिलिपि बनाई जानी चाहिए (साथ ही अंत में जोड़े गए कुछ नए)। तो (सादगी के लिए और सामान्यता के वास्तविक नुकसान के बिना) का कहना है कि आपके पास प्रत्येक आइटम के एल उपन्यास हैं: पहले आइटमों को एल-1 बार पीछे और पीछे कॉपी किया गया है, दूसरा मैं एल-2 बार आइटम करता हूं, और इसी तरह; प्रतियों की कुल संख्या मैं x के लिए एक्स के योग को 1 से एल तक छोड़ देता I * (L**2)/2 , यानी, I * (L**2)/2

सूची की समझ सिर्फ एक सूची उत्पन्न करती है, एक बार, और प्रत्येक आइटम को प्रतिस्थापित करता है (निवास की मूल स्थान से परिणाम सूची में) बिल्कुल एक बार।





flatten