python - আপনি কিভাবে সমান মাপের অংশে একটি তালিকা বিভক্ত করবেন?




list split (20)

এখানে অন্যান্য উত্তর এর সমালোচনা:

এই উত্তরগুলির মধ্যে কেউই সমান আকারের অংশ নয়, তারা সব শেষে একটি রান্ট ছিনতাই ছেড়ে দেয়, তাই তারা সম্পূর্ণরূপে সুষম হয় না। আপনি যদি কাজটি বিতরণ করার জন্য এই ফাংশনগুলি ব্যবহার করেন, তবে আপনি অন্যের সামনে ভালভাবে সম্পন্ন হওয়ার সম্ভাবনাটি তৈরি করেছেন, তাই অন্যেরা যখন কঠোর পরিশ্রম চালিয়ে যাচ্ছিল তখন এটি প্রায় কিছুই করতে পারত না।

উদাহরণস্বরূপ, বর্তমান শীর্ষ উত্তর দিয়ে শেষ হয়:

[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74]]

আমি শুধু শেষ পর্যন্ত যে runt ঘৃণা!

অন্যের মতো list(grouper(3, xrange(7))) , এবং chunk(xrange(7), 3) উভয় প্রত্যাবর্তন: [(0, 1, 2), (3, 4, 5), (6, None, None)]None শুধু প্যাডিং, এবং আমার মতে বরং মার্জিত। তারা সমানভাবে iterables chunking হয় না।

কেন আমরা এই ভাল বিভক্ত করা যাবে না?

আমার সমাধান (গুলি)

এখানে একটি ভারসাম্য সমাধান, যা আমি ব্যবহারে ব্যবহৃত একটি ফাংশন থেকে গৃহীত (পাইথন 3 এ দ্রষ্টব্য সহ xrange প্রতিস্থাপন করার জন্য xrange ):

def baskets_from(items, maxbaskets=25):
    baskets = [[] for _ in xrange(maxbaskets)] # in Python 3 use range
    for i, item in enumerate(items):
        baskets[i % maxbaskets].append(item)
    return filter(None, baskets) 

এবং আমি একটি জেনারেটর তৈরি করেছি যা আপনি যদি এটি একটি তালিকাতে রাখেন তবে একই কাজ করে:

def iter_baskets_from(items, maxbaskets=3):
    '''generates evenly balanced baskets from indexable iterable'''
    item_count = len(items)
    baskets = min(item_count, maxbaskets)
    for x_i in xrange(baskets):
        yield [items[y_i] for y_i in xrange(x_i, item_count, baskets)]

এবং অবশেষে, যেহেতু আমি দেখি যে উপরের সমস্ত ফাংশনগুলি একটি নির্দিষ্ট ক্রম অনুসারে উপাদানগুলিকে ফিরিয়ে দেয় (যেমনটি দেওয়া হয়েছিল):

def iter_baskets_contiguous(items, maxbaskets=3, item_count=None):
    '''
    generates balanced baskets from iterable, contiguous contents
    provide item_count if providing a iterator that doesn't support len()
    '''
    item_count = item_count or len(items)
    baskets = min(item_count, maxbaskets)
    items = iter(items)
    floor = item_count // baskets 
    ceiling = floor + 1
    stepdown = item_count % baskets
    for x_i in xrange(baskets):
        length = ceiling if x_i < stepdown else floor
        yield [items.next() for _ in xrange(length)]

আউটপুট

তাদের পরীক্ষা করার জন্য:

print(baskets_from(xrange(6), 8))
print(list(iter_baskets_from(xrange(6), 8)))
print(list(iter_baskets_contiguous(xrange(6), 8)))
print(baskets_from(xrange(22), 8))
print(list(iter_baskets_from(xrange(22), 8)))
print(list(iter_baskets_contiguous(xrange(22), 8)))
print(baskets_from('ABCDEFG', 3))
print(list(iter_baskets_from('ABCDEFG', 3)))
print(list(iter_baskets_contiguous('ABCDEFG', 3)))
print(baskets_from(xrange(26), 5))
print(list(iter_baskets_from(xrange(26), 5)))
print(list(iter_baskets_contiguous(xrange(26), 5)))

যা প্রিন্ট আউট:

[[0], [1], [2], [3], [4], [5]]
[[0], [1], [2], [3], [4], [5]]
[[0], [1], [2], [3], [4], [5]]
[[0, 8, 16], [1, 9, 17], [2, 10, 18], [3, 11, 19], [4, 12, 20], [5, 13, 21], [6, 14], [7, 15]]
[[0, 8, 16], [1, 9, 17], [2, 10, 18], [3, 11, 19], [4, 12, 20], [5, 13, 21], [6, 14], [7, 15]]
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14], [15, 16, 17], [18, 19], [20, 21]]
[['A', 'D', 'G'], ['B', 'E'], ['C', 'F']]
[['A', 'D', 'G'], ['B', 'E'], ['C', 'F']]
[['A', 'B', 'C'], ['D', 'E'], ['F', 'G']]
[[0, 5, 10, 15, 20, 25], [1, 6, 11, 16, 21], [2, 7, 12, 17, 22], [3, 8, 13, 18, 23], [4, 9, 14, 19, 24]]
[[0, 5, 10, 15, 20, 25], [1, 6, 11, 16, 21], [2, 7, 12, 17, 22], [3, 8, 13, 18, 23], [4, 9, 14, 19, 24]]
[[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20], [21, 22, 23, 24, 25]]

লক্ষ্য করুন যে সামঞ্জস্যপূর্ণ জেনারেটর অন্যান্য দুইটির মতো একই দৈর্ঘ্যের প্যাটার্নগুলিকে সরবরাহ করে তবে আইটেমগুলি ক্রম অনুসারে সাজানো হয় এবং পৃথক পৃথক বিভাজনগুলির তালিকায় বিভক্ত হিসাবে সমানভাবে ভাগ করা হয়।

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

আমি যে কোন দৈর্ঘ্যের তালিকা, যেমন জেনারেটর ব্যবহার করে এই জন্য একটি ভাল সমাধান ছিল, যদি আমি বিস্মিত ছিল।

আমি itertools দরকারী কিছু খুঁজছেন কিন্তু আমি স্পষ্টভাবে দরকারী কিছু খুঁজে পাচ্ছি না। যদিও এটা মিস করেছি।

সম্পর্কিত প্রশ্ন: অংশে একটি তালিকা পুনরাবৃত্তি করার সবচেয়ে "পাইথনিক" উপায় কি?


আপনি utilspie লাইব্রেরীর get_chunks ফাংশনটিও ব্যবহার করতে পারেন:

>>> from utilspie import iterutils
>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> list(iterutils.get_chunks(a, 5))
[[1, 2, 3, 4, 5], [6, 7, 8, 9]]

আপনি পিপ মাধ্যমে utilspie ইনস্টল করতে পারেন:

sudo pip install utilspie

Disclaimer: আমি utilspie লাইব্রেরি এর নির্মাতা


আমি অবাক হচ্ছি যে কেউ iter দ্বি-যুক্তি ফর্মটি ব্যবহার করার চিন্তা করেনি:

from itertools import islice

def chunk(it, size):
    it = iter(it)
    return iter(lambda: tuple(islice(it, size)), ())

ডেমো:

>>> list(chunk(range(14), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13)]

এই কোনো পুনরাবৃত্ত সঙ্গে কাজ করে এবং অলস আউটপুট উত্পাদন করে। এটা বরং iterators তুলনায় tuples ফেরত, কিন্তু আমি মনে করি এটি একটি নির্দিষ্ট কমনীয়তা আছে। এটা প্যাড না; আপনি প্যাডিং চান, উপরে একটি সহজ পার্থক্য যথেষ্ট হবে:

from itertools import islice, chain, repeat

def chunk_pad(it, size, padval=None):
    it = chain(iter(it), repeat(padval))
    return iter(lambda: tuple(islice(it, size)), (padval,) * size)

ডেমো:

>>> list(chunk_pad(range(14), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, None)]
>>> list(chunk_pad(range(14), 3, 'a'))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 'a')]

izip_longest ভিত্তিক সমাধান মত, উপরে সবসময় প্যাড। যতদূর আমি জানি, বিকল্পভাবে প্যাড যে একটি ফাংশন জন্য কোন এক- বা দুই লাইন itertools রেসিপি নেই। উপরের দুটি পদ্ধতির সমন্বয় করে, এটি একদম কাছাকাছি আসে:

_no_padding = object()

def chunk(it, size, padval=_no_padding):
    if padval == _no_padding:
        it = iter(it)
        sentinel = ()
    else:
        it = chain(iter(it), repeat(padval))
        sentinel = (padval,) * size
    return iter(lambda: tuple(islice(it, size)), sentinel)

ডেমো:

>>> list(chunk(range(14), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13)]
>>> list(chunk(range(14), 3, None))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, None)]
>>> list(chunk(range(14), 3, 'a'))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 'a')]

আমি বিশ্বাস করি যে এই সংক্ষিপ্ত চংকর প্রস্তাবিত যে ঐচ্ছিক প্যাডিং প্রস্তাব।

টমাস্জ গণ্ডারের observed , দুটি প্যাডিং চংকর যদি প্যাড মানগুলির লম্বা অনুক্রমের সম্মুখীন হয় তবে তারা অপ্রত্যাশিতভাবে বন্ধ হয়ে যাবে। এখানে একটি চূড়ান্ত বৈচিত্র্য রয়েছে যা যুক্তিসঙ্গতভাবে সেই সমস্যাটির চারপাশে কাজ করে:

_no_padding = object()
def chunk(it, size, padval=_no_padding):
    it = iter(it)
    chunker = iter(lambda: tuple(islice(it, size)), ())
    if padval == _no_padding:
        yield from chunker
    else:
        for ch in chunker:
            yield ch if len(ch) == size else ch + (padval,) * (size - len(ch))

ডেমো:

>>> list(chunk([1, 2, (), (), 5], 2))
[(1, 2), ((), ()), (5,)]
>>> list(chunk([1, 2, None, None, 5], 2, None))
[(1, 2), (None, None), (5, None)]

আমি এই প্রশ্নের duplicate সবচেয়ে ভয়ঙ্কর পাইথন-ইসহ উত্তর দেখেছি:

from itertools import zip_longest

a = range(1, 16)
i = iter(a)
r = list(zip_longest(i, i, i))
>>> print(r)
[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12), (13, 14, 15)]

আপনি n এর জন্য n-tuple তৈরি করতে পারেন। a = range(1, 15) , তাহলে ফলাফল হবে:

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

তালিকাটি সমানভাবে বিভক্ত হলে, আপনি zip_longest zip দিয়ে প্রতিস্থাপন করতে পারেন, অন্যথায় ট্রিপলেটটি (13, 14, None) হারিয়ে যাবে না। পাইথন 3 উপরে ব্যবহৃত হয়। পাইথন 2 এর জন্য, izip_longest ব্যবহার izip_longest


আমি পাইজন ডক এর সংস্করণটি টিজোট এবং জেএফএসবেস্টিয়ান দ্বারা প্রস্তাবিত অনেক পছন্দ করি, তবে এতে দুটি ত্রুটি রয়েছে:

  • এটা খুব স্পষ্ট নয়
  • আমি সাধারণত শেষ অংশে একটি ভরাট মান চান না

আমি এই কোডটি আমার কোডে অনেক ব্যবহার করছি:

from itertools import islice

def chunks(n, iterable):
    iterable = iter(iterable)
    while True:
        yield tuple(islice(iterable, n)) or iterable.next()

আপডেট: একটি অলস অংশ সংস্করণ:

from itertools import chain, islice

def chunks(n, iterable):
   iterable = iter(iterable)
   while True:
       yield chain([next(iterable)], islice(iterable, n-1))

আমি বিভিন্ন পদ্ধতির কর্মক্ষমতা সম্পর্কে অদ্ভুত ছিল এবং এখানে:

পাইথন 3.5.1 পরীক্ষা করা

import time
batch_size = 7
arr_len = 298937

#---------slice-------------

print("\r\nslice")
start = time.time()
arr = [i for i in range(0, arr_len)]
while True:
    if not arr:
        break

    tmp = arr[0:batch_size]
    arr = arr[batch_size:-1]
print(time.time() - start)

#-----------index-----------

print("\r\nindex")
arr = [i for i in range(0, arr_len)]
start = time.time()
for i in range(0, round(len(arr) / batch_size + 1)):
    tmp = arr[batch_size * i : batch_size * (i + 1)]
print(time.time() - start)

#----------batches 1------------

def batch(iterable, n=1):
    l = len(iterable)
    for ndx in range(0, l, n):
        yield iterable[ndx:min(ndx + n, l)]

print("\r\nbatches 1")
arr = [i for i in range(0, arr_len)]
start = time.time()
for x in batch(arr, batch_size):
    tmp = x
print(time.time() - start)

#----------batches 2------------

from itertools import islice, chain

def batch(iterable, size):
    sourceiter = iter(iterable)
    while True:
        batchiter = islice(sourceiter, size)
        yield chain([next(batchiter)], batchiter)


print("\r\nbatches 2")
arr = [i for i in range(0, arr_len)]
start = time.time()
for x in batch(arr, batch_size):
    tmp = x
print(time.time() - start)

#---------chunks-------------
def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in range(0, len(l), n):
        yield l[i:i + n]
print("\r\nchunks")
arr = [i for i in range(0, arr_len)]
start = time.time()
for x in chunks(arr, batch_size):
    tmp = x
print(time.time() - start)

#-----------grouper-----------

from itertools import zip_longest # for Python 3.x
#from six.moves import zip_longest # for both (uses the six compat library)

def grouper(iterable, n, padvalue=None):
    "grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
    return zip_longest(*[iter(iterable)]*n, fillvalue=padvalue)

arr = [i for i in range(0, arr_len)]
print("\r\ngrouper")
start = time.time()
for x in grouper(arr, batch_size):
    tmp = x
print(time.time() - start)

ফলাফল:

slice
31.18285083770752

index
0.02184295654296875

batches 1
0.03503894805908203

batches 2
0.22681021690368652

chunks
0.019841909408569336

grouper
0.006506919860839844

এই মুহুর্তে, আমি মনে করি আমরা একটি recursive জেনারেটরের প্রয়োজন, ঠিক ক্ষেত্রে ...

পাইথন 2:

def chunks(li, n):
    if li == []:
        return
    yield li[:n]
    for e in chunks(li[n:], n):
        yield e

পাইথন 3:

def chunks(li, n):
    if li == []:
        return
    yield li[:n]
    yield from chunks(li[n:], n)

এছাড়াও, বৃহদায়তন এলিয়েন আক্রমণের ক্ষেত্রে, সজ্জিত পুনরাবৃত্ত জেনারেটরটি সহজ হতে পারে:

def dec(gen):
    def new_gen(li, n):
        for e in gen(li, n):
            if e == []:
                return
            yield e
    return new_gen

@dec
def chunks(li, n):
    yield li[:n]
    for e in chunks(li[n:], n):
        yield e

একটি জেনারেটর এক্সপ্রেশন:

def chunks(seq, n):
    return (seq[i:i+n] for i in xrange(0, len(seq), n))

যেমন।

print list(chunks(range(1, 1000), 10))

এখানে একটি জেনারেটর যা ইচ্ছাকৃত iterables উপর কাজ করে:

def split_seq(iterable, size):
    it = iter(iterable)
    item = list(itertools.islice(it, size))
    while item:
        yield item
        item = list(itertools.islice(it, size))

উদাহরণ:

>>> import pprint
>>> pprint.pprint(list(split_seq(xrange(75), 10)))
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
 [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
 [20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
 [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
 [40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
 [50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
 [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
 [70, 71, 72, 73, 74]]

কোড:

def split_list(the_list, chunk_size):
    result_list = []
    while the_list:
        result_list.append(the_list[:chunk_size])
        the_list = the_list[chunk_size:]
    return result_list

a_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

print split_list(a_list, 3)

ফলাফল:

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

সরাসরি (পুরাতন) পাইথন ডকুমেন্টেশন থেকে (itertools জন্য রেসিপি):

from itertools import izip, chain, repeat

def grouper(n, iterable, padvalue=None):
    "grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
    return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)

JFSebastian দ্বারা প্রস্তাবিত বর্তমান সংস্করণ:

#from itertools import izip_longest as zip_longest # for Python 2.x
from itertools import zip_longest # for Python 3.x
#from six.moves import zip_longest # for both (uses the six compat library)

def grouper(n, iterable, padvalue=None):
    "grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
    return zip_longest(*[iter(iterable)]*n, fillvalue=padvalue)

আমি Guido এর সময় মেশিন কাজ-কাজ-কাজ করবে-কাজ করবে-আবার কাজ ছিল অনুমান।

এই সমাধানগুলি কাজ করে কারণ [iter(iterable)]*n (বা পূর্ববর্তী সংস্করণের সমতুল্য) একটি ইটারেটর তৈরি করে, তালিকাটিতে বার বার পুনরাবৃত্তি করে। izip_longest তারপর কার্যকরভাবে "প্রতিটি" izip_longest একটি বৃত্তাকার রবিন সঞ্চালন; কারণ এটি একই ইটারারেটর, এটি প্রতিটি যেমন কল দ্বারা উন্নত হয়, যার ফলে প্রতিটি যেমন জিপ-রাউন্ডারবিন n আইটেমগুলির একটি টিপল তৈরি করে।


সহজ এখনো মার্জিত

l = range(1, 1000)
print [l[x:x+10] for x in xrange(0, len(l), 10)]

অথবা আপনি যদি পছন্দ করেন:

chunks = lambda l, n: [l[x: x+n] for x in xrange(0, len(l), n)]
chunks(l, 10)

toolz লাইব্রেরিটির জন্য partition ফাংশন রয়েছে:

from toolz.itertoolz.core import partition

list(partition(2, [1, 2, 3, 4]))
[(1, 2), (3, 4)]

আমি এই প্রশ্নটি পুরাতন (গুগল এ এটির উপর চাপিয়ে দিয়েছি) বুঝতে পারছি, তবে নিচের মতো কিছু জটিল জটিল পরামর্শগুলির চেয়ে অনেক সহজ এবং স্পষ্ট এবং কেবলমাত্র ধুলো ব্যবহার করে:

def chunker(iterable, chunksize):
    for i,c in enumerate(iterable[::chunksize]):
        yield iterable[i*chunksize:(i+1)*chunksize]

>>> for chunk in chunker(range(0,100), 10):
...     print list(chunk)
... 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
... etc ...

আরেকটি আরো সুস্পষ্ট সংস্করণ।

def chunkList(initialList, chunkSize):
    """
    This function chunks a list into sub lists 
    that have a length equals to chunkSize.

    Example:
    lst = [3, 4, 9, 7, 1, 1, 2, 3]
    print(chunkList(lst, 3)) 
    returns
    [[3, 4, 9], [7, 1, 1], [2, 3]]
    """
    finalList = []
    for i in range(0, len(initialList), chunkSize):
        finalList.append(initialList[i:i+chunkSize])
    return finalList

এই মুহুর্তে, আমি মনে করি আমাদের বাধ্যতামূলক বেনামী-পুনরাবৃত্তি ফাংশন প্রয়োজন।

Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
chunks = Y(lambda f: lambda n: [n[0][:n[1]]] + f((n[0][n[1]:], n[1])) if len(n[0]) > 0 else [])

matplotlib.cbook টুকরা ব্যবহার বিবেচনা করুন

উদাহরণ স্বরূপ:

import matplotlib.cbook as cbook
segments = cbook.pieces(np.arange(20), 3)
for s in segments:
     print s

def chunk(input, size):
    return map(None, *([iter(input)] * size))

def split_seq(seq, num_pieces):
    start = 0
    for i in xrange(num_pieces):
        stop = start + len(seq[i::num_pieces])
        yield seq[start:stop]
        start = stop

ব্যবহার:

seq = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

for seq in split_seq(seq, 3):
    print seq

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
CHUNK = 4
[a[i*CHUNK:(i+1)*CHUNK] for i in xrange((len(a) + CHUNK - 1) / CHUNK )]




chunks