python - তালিকা তালিকা থেকে একটি সমতল তালিকা কিভাবে?




15 Answers

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 = 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

ব্যাখ্যা: উপর ভিত্তি করে শর্টকাটগুলি (সমষ্টিতে নিখরচায় ব্যবহার সহ), প্রয়োজনের, O(L**2) যখন এল sublists হয় - যেমন মধ্যবর্তী ফলাফল তালিকা দীর্ঘতর থাকে, প্রতিটি ধাপে একটি নতুন মধ্যবর্তী ফলাফল তালিকা বস্তু বরাদ্দ করা হয়, এবং পূর্ববর্তী মধ্যবর্তী ফলাফলের সমস্ত আইটেম অনুলিপি করা উচিত (পাশাপাশি শেষে যুক্ত কয়েকটি নতুন)। সুতরাং (সরলতার জন্য এবং সাধারণভাবে প্রকৃত ক্ষতি না করে) বলুন আপনার প্রতিটি আইটেমগুলির এল Sublists আছে: প্রথম আইটেমটি আমি L-1 বার, দ্বিতীয় আইটেম L-2 বার এবং আরও অনুলিপি করা হয়; মোট কপিগুলির সংখ্যা আমি বার বার 1 থেকে এক্স এর জন্য এক্স এর সমষ্টি, অর্থাৎ, I * (L**2)/2

তালিকা বোঝার কেবল একটি তালিকা তৈরি করে, একবার, এবং প্রতিটি আইটেমকে অনুলিপি করে (বাসস্থানটির আসল স্থানে থেকে ফলাফল তালিকায়) ঠিক একই সময়ে।

Python এ তালিকাগুলির তালিকা থেকে একটি সহজ তালিকা তৈরি করার জন্য একটি শর্টকাট আছে কিনা আমি অবাক।

আমি একটি লুপ জন্য যে করতে পারেন, কিন্তু সম্ভবত কিছু শীতল "এক-মাছ ধরার নৌকা" আছে? আমি এটি কমাতে চেষ্টা করেছি, কিন্তু আমি একটি ত্রুটি পেতে।

কোড

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'



লেখক থেকে নোট : এই অদক্ষ। কিন্তু মজা, monads ভয়ঙ্কর কারণ। এটা পাইথন কোড উত্পাদন জন্য উপযুক্ত নয়।

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

এটি কেবলমাত্র প্রথম যুক্তিটিতে প্রেরণযোগ্য উপাদানগুলিকে গণনা করে, দ্বিতীয় আর্গুমেন্টকে সমষ্টিগত প্রাথমিক মান হিসেবে বিবেচনা করে (যদি না দেওয়া হয়, 0 পরিবর্তে ব্যবহৃত হয় এবং এই ক্ষেত্রে আপনাকে একটি ত্রুটি দেবে)।

কারণ আপনি নেস্টেড তালিকাগুলি সংকলন করছেন, আপনি প্রকৃতপক্ষে [1,3]+[2,4] sum([[1,3],[2,4]],[]) ফলে পাবেন যা [1,3,2,4]

তালিকা তালিকা শুধুমাত্র কাজ করে নোট। তালিকা তালিকা তালিকা জন্য, আপনি অন্য সমাধান প্রয়োজন হবে।




from functools import reduce #python 3

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

আপনার উদাহরণে extend() পদ্ধতিটি একটি কার্যকর মান (যা প্রত্যাশা করে) প্রত্যাহারের পরিবর্তে x পরিবর্তন করে।

reduce সংস্করণ করতে একটি দ্রুত উপায় হবে

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



আমি ফিরে আমার বিবৃতি নিতে। চূড়ান্ত বিজয়ী নয়। তালিকাটি ছোট হলেও এটি দ্রুত। কিন্তু কর্মক্ষমতা বড় তালিকা সঙ্গে উল্লেখযোগ্যভাবে হ্রাস।

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



যদি আপনি কোনও তথ্য-কাঠামোকে ফ্ল্যাট করতে চান যেখানে আপনি এটি গভীরভাবে নিস্তেজ না হন তবে এটি 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 নিক্ষেপ করতে বা স্পষ্টভাবে এটির পুনরাবৃত্তি করতে হবে।

কেবলমাত্র এক স্তরকে ফ্ল্যাট করতে এবং যদি প্রতিটি আইটেম নিজেই কার্যকর হয় তবে আপনি iteration_utilities.flatten ব্যবহার করতে পারেন যা নিজেই itertools.chain.from_iterable কাছাকাছি একটি পাতলা মোড়ক 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]

শুধু কিছু সময় যোগ করার জন্য (নিক Schlömer উত্তরটির উপর ভিত্তি করে যা এই উত্তরটিতে উপস্থাপিত ফাংশনটি অন্তর্ভুক্ত করে নি):

এটি একটি লগ-লগ প্লট যা ব্যয়বহুল মানগুলির বিস্তৃত পরিসরের জন্য উপযুক্ত। গুণগত যুক্তি জন্য: নিম্নতর ভাল।

ফলাফলগুলি দেখায় যে যদি কেবলমাত্র কয়েকটি অভ্যন্তরীণ ইথারবেল থাকে তবে sum দ্রুততম হবে, তবে itertools.chain.from_iterable জন্য শুধুমাত্র itertools.chain.from_iterable , iteration_utilities.deepflatten বা nested বোঝার সাথে itertools.chain.from_iterable দ্রুততম কার্যকারিতা রয়েছে (ইতিমধ্যে নিক Schlömer দ্বারা লক্ষ্য করেছেন)।

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 দাবিঃ আমি সেই লাইব্রেরীর লেখক




আপনার ফাংশন কাজ করে না কারণ: প্রসারিত অ্যারে প্রসারিত এবং এটি ফেরত না। আপনি এখনও কিছু কৌশল ব্যবহার করে, ল্যাম্বা থেকে এক্সটি ফিরে পেতে পারেন:

reduce(lambda x,y: x.extend(y) or x, l)

দ্রষ্টব্য: তালিকা থেকে + বেশি কার্যকর প্রসারিত।




অনিলের ফাংশনটির একটি খারাপ বৈশিষ্ট্য হল ব্যবহারকারীকে সর্বদা একটি খালি তালিকা হতে দ্বিতীয় যুক্তিটি নির্দিষ্ট করতে হবে [] । এটি পরিবর্তে একটি ডিফল্ট হতে হবে। পাইথন বস্তুগুলি যেভাবে কাজ করে, তার কারণে এইগুলি ফাংশনের ভিতরে সেট করা উচিত, আর্গুমেন্টে নয়।

এখানে একটি কাজ ফাংশন:

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]



নিম্নলিখিত আমার কাছে সহজ মনে হয়:

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



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 দ্রুত ._। ফ্ল্যাট:

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



আপনি numpy ব্যবহার করতে পারেন:
flat_list = list(np.concatenate(list_of_list))




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

এই কোডটি ঠিক ভাবেই তালিকাটি প্রসারিত করে জরিমানা করে। যদিও এটি অনেক অনুরূপ কিন্তু শুধুমাত্র লুপের জন্য একটি। তাই loops জন্য 2 যোগ চেয়ে কম জটিলতা আছে।




আমি দ্রুততম সমাধান খুঁজে পেয়েছি (যাইহোক বড় তালিকা জন্য):

import numpy as np
#turn list into an array and flatten()
np.array(l).flatten()

সম্পন্ন! আপনি অবশ্যই তালিকাটি নির্বাহ করে এটি একটি তালিকাতে ফিরিয়ে আনতে পারেন (l)




দ্রষ্টব্য : এটি ব্যবহার করে কারণ পাইথন 3.3+ এ প্রযোজ্য yield_fromsixএটি একটি তৃতীয় পক্ষের প্যাকেজ, যদিও এটি স্থিতিশীল। অন্যথায়, আপনি ব্যবহার করতে পারেন sys.version

ক্ষেত্রে obj = [[1, 2,], [3, 4], [5, 6]], এখানে সমস্ত সমাধান তালিকা বোঝার সহ, ভাল itertools.chain.from_iterable

তবে, এই সামান্য আরো জটিল ক্ষেত্রে বিবেচনা করুন:

>>> obj = [[1, 2, 3], [4, 5], 6, 'abc', [7], [8, [9, 10]]]

এখানে বিভিন্ন সমস্যা আছে:

  • এক উপাদান,, 6শুধু একটি scalar হয়; এটি পুনরাবৃত্তিযোগ্য নয়, তাই উপরের রুট এখানে ব্যর্থ হবে।
  • এক উপাদান 'abc', হয় টেকনিক্যালি iterable (সমস্ত strগুলি আছে)। যাইহোক, লাইনগুলির মধ্যে একটু পড়া, আপনি এটির মতো আচরণ করতে চান না - আপনি এটি একটি একক উপাদান হিসাবে আচরণ করতে চান।
  • চূড়ান্ত উপাদান, [8, [9, 10]]নিজেই একটি nested পুনরাবৃত্তিযোগ্য। বেসিক তালিকা বোঝার এবং chain.from_iterableশুধুমাত্র "1 স্তর নিচে।"

আপনি নিম্নরূপ এই প্রতিকার করতে পারেন:

>>> from collections import Iterable
>>> from six import string_types

>>> def flatten(obj):
...     for i in obj:
...         if isinstance(i, Iterable) and not isinstance(i, string_types):
...             yield from flatten(i)
...         else:
...             yield i


>>> list(flatten(obj))
[1, 2, 3, 4, 5, 6, 'abc', 7, 8, 9, 10]

এখানে, আপনি চেক করুন যে উপ-উপাদান (1) সঙ্গে iterable হয় Iterable, থেকে একটি এবিসি itertools, কিন্তু তা নিশ্চিত করার জন্য (2) উপাদান চান না "STRING মত।"




এটি সবচেয়ে কার্যকরী উপায় হতে পারে না তবে আমি একটি এক-মাছ ধরার নৌকা (আসলে একটি দুই-মাছ ধরার নৌকা) লাগাতে চিন্তা। উভয় সংস্করণ ইচ্ছাকৃতভাবে অনুক্রমের তালিকাভুক্ত নেস্টেড তালিকাগুলিতে কাজ করবে এবং ভাষা বৈশিষ্ট্যগুলি (Python3.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নীচের মত একটি gloabl তৈরি হতে পারে মনে হয় ।

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]

আমি দক্ষতা সম্পর্কে এই সময়ে নিশ্চিত না হলেও।




Related

python list multidimensional-array flatten