كيف يمكنك تقسيم القائمة إلى أجزاء متساوية الحجم؟

StackOverflow https://stackoverflow.com/questions/312443

  •  10-07-2019
  •  | 
  •  

سؤال

لدي قائمة ذات طول عشوائي، وأحتاج إلى تقسيمها إلى أجزاء متساوية الحجم والعمل عليها.هناك بعض الطرق الواضحة للقيام بذلك، مثل الاحتفاظ بعداد وقائمتين، وعندما تمتلئ القائمة الثانية، قم بإضافتها إلى القائمة الأولى وإفراغ القائمة الثانية للجولة التالية من البيانات، ولكن من المحتمل أن يكون هذا مكلفًا للغاية.

كنت أتساءل عما إذا كان لدى أي شخص حل جيد لهذا لقوائم بأي طول، على سبيل المثال.باستخدام المولدات.

كنت أبحث عن شيء مفيد في itertools لكنني لم أجد أي شيء مفيد بشكل واضح.ربما فاتني ذلك، رغم ذلك.

سؤال ذو صلة: ما هي الطريقة الأكثر "بيثونية" للتكرار على قائمة في أجزاء؟

هل كانت مفيدة؟

المحلول

وهنا المولدات التي تعطي مساحات تريد:

def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in range(0, len(l), n):
        yield l[i:i + n]

import pprint
pprint.pprint(list(chunks(range(10, 75), 10)))
[[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]]

إذا كنت تستخدم بايثون 2، يجب عليك استخدام xrange() بدلا من range():

def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in xrange(0, len(l), n):
        yield l[i:i + n]

وأيضا يمكنك ببساطة استخدام الفهم قائمة بدلا من كتابة وظيفة، على الرغم من انها فكرة جيدة لتغليف مثل هذه العمليات في وظائف اسمه بحيث التعليمات البرمجية أسهل للفهم. بيثون 3:

[l[i:i + n] for i in range(0, len(l), n)]

وبايثون 2 نسخة:

[l[i:i + n] for i in xrange(0, len(l), n)]

نصائح أخرى

إذا كنت تريد شيئا السوبر بسيط:

def chunks(l, n):
    n = max(1, n)
    return (l[i:i+n] for i in xrange(0, len(l), n))

استخدم range() بدلا من xrange() في حالة بيثون 3.X

ومباشرة من (القديمة) وثائق بيثون (وصفات ل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)

والإصدار الحالي، على النحو الذي اقترحه J.F.Sebastian:

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

وأعتقد غيدو الوقت المصنفات عمل، وآلة العمل، وعملت، والعمل مرة أخرى.

وهذه الحلول تعمل ل[iter(iterable)]*n (أو ما يعادلها في إصدار سابق) بإنشاء <م> واحدة مكرر، وأحيانا n تتكرر في القائمة. izip_longest ثم ينفذ بشكل فعال على بعد جولة روبن من "كل" مكرر. لأن هذا هو نفس مكرر، وتقدمت من قبل كل تلك الدعوة، مما أدى إلى كل هذا الرمز البريدي roundrobin توليد الصفوف (tuple) أحد البنود n.

وأنا أعلم أن هذا هو نوع من العمر ولكن أنا لا لماذا لا أحد ذكر numpy.array_split:

lst = range(50)
In [26]: np.array_split(lst,5)
Out[26]: 
[array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
 array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
 array([20, 21, 22, 23, 24, 25, 26, 27, 28, 29]),
 array([30, 31, 32, 33, 34, 35, 36, 37, 38, 39]),
 array([40, 41, 42, 43, 44, 45, 46, 47, 48, 49])]
ويعتقد

وأنا لا أحد بالدهشة استخدام 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)]

وهذا يعمل مع أي iterable وينتج إخراج بتكاسل. فإنها ترجع الصفوف بدلا من التكرارات، ولكن أعتقد أن لديها الأناقة معينة مع ذلك. فإنه أيضا لا منصة، إذا كنت تريد الحشو، والاختلاف بسيط على ما سبق يكفي:

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

وأعتقد أن هذا هو أقصر chunker المقترحة التي تقدم الحشو اختياري.

وأما توماس Gandor <لأ href = "https://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks/22045226؟noredirect=1#comment93566337_22045226 "> لاحظ ، و سيتم إيقاف اثنين من chunkers الحشو بشكل غير متوقع إذا كانت تواجه سلسلة طويلة من القيم وسادة. وهنا الاختلاف النهائي الذي يعمل حول هذه المشكلة بطريقة معقولة:

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

وهنا هو مولد التي تعمل على 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 chunk(input, size):
    return map(None, *([iter(input)] * size))

وبسيط وأنيق

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)

لقد رأيت إجابة Python-ish الأكثر روعة في ملف ينسخ من هذا السؤال:

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-tuple لأي n.لو 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) سوف تضيع.تم استخدام Python 3 أعلاه.بالنسبة لبيثون 2، استخدم izip_longest.

نقد الإجابات الأخرى هنا:

لا تحتوي أي من هذه الإجابات على أجزاء متساوية الحجم، بل تترك جميعها جزءًا صغيرًا في النهاية، لذا فهي ليست متوازنة تمامًا.إذا كنت تستخدم هذه الوظائف لتوزيع العمل، فقد بنيت في احتمال أن ينتهي أحدهم قبل الآخرين بفترة طويلة، لذلك سيجلس دون فعل أي شيء بينما يواصل الآخرون العمل الجاد.

على سبيل المثال، تنتهي الإجابة الحالية بـ:

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

أنا فقط أكره هذا القزم في النهاية!

آخرون، مثل list(grouper(3, xrange(7))), ، و chunk(xrange(7), 3) كلاهما يعود: [(0, 1, 2), (3, 4, 5), (6, None, None)].ال Noneإنها مجرد حشوة، وغير أنيقة إلى حد ما في رأيي.إنهم لا يقومون بتقطيع العناصر التكرارية بالتساوي.

لماذا لا يمكننا تقسيم هذه بشكل أفضل؟

الحل الخاص بي (الحلول)

إليك حل متوازن، مقتبس من وظيفة استخدمتها في الإنتاج (لاحظ في Python 3 لاستبدال xrange مع range):

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

لاحظ أن المولد المتجاور يوفر قطعًا بنفس أنماط الطول مثل المولدين الآخرين، ولكن العناصر كلها مرتبة، وهي مقسمة بالتساوي كما يمكن تقسيم قائمة من العناصر المنفصلة.

إذا كنت تعرف حجم القائمة:

def SplitList(mylist, chunk_size):
    return [mylist[offs:offs+chunk_size] for offs in range(0, len(mylist), chunk_size)]

إذا كنت لا (مكرر):

def IterChunks(sequence, chunk_size):
    res = []
    for item in sequence:
        res.append(item)
        if len(res) >= chunk_size:
            yield res
            res = []
    if res:
        yield res  # yield the last, incomplete, portion

في هذه الحالة الأخيرة، يمكن إعادة صياغة بطريقة أكثر جمالا إذا كان يمكنك أن تتأكد من أن تسلسل يحتوي دائما عددا كاملا من قطع من حجم معين (أي لا يوجد غير مكتملة قطعة الماضية).

إذا كان لديك حجم قطعة من 3 على سبيل المثال، يمكن أن تفعله:

zip(*[iterable[i::3] for i in range(3)]) 

المصدر: http://code.activestate.com/recipes/303060-group -a القائمة حيز متتابعة ن الصفوف /

وأود أن استخدام هذا الرقم عند ثابتة مقاسي قطعة استطيع ان اكتب، على سبيل المثال '3'، وسوف لا تتغير أبدا.

تولز مكتبة لديه وظيفة partition لذلك:

from toolz.itertoolz.core import partition

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

أحب نسخة Python Doc التي اقترحتها Tzot و Jfsebastian كثيرًا ، ولكن لديها عيوبان:

  • انها ليست واضحة جدا
  • عادةً لا أريد قيمة تعبئة في الجزء الأخير

أنا أستخدم هذا كثيرًا في الكود الخاص بي:

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

في هذه المرحلة، أعتقد أننا بحاجة إلى مولد العودي, ، فقط في حالة...

في بيثون 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

ويمكنك أيضا استخدام get_chunks ظيفة <أ href = على "HTTP : //utilspie.readthedocs.io "يختلط =" noreferrer "> utilspie مكتبة النحو التالي:

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

تنويه: انا خالق utilspie مكتبة

لقد كنت أشعر بالفضول بشأن أداء الأساليب المختلفة وهنا:

تم اختباره على بايثون 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
[AA[i:i+SS] for i in range(len(AA))[::SS]]

وأين AA هو مجموعة، SS هو حجم قطعة. على سبيل المثال:

>>> AA=range(10,21);SS=3
>>> [AA[i:i+SS] for i in range(len(AA))[::SS]]
[[10, 11, 12], [13, 14, 15], [16, 17, 18], [19, 20]]
# or [range(10, 13), range(13, 16), range(16, 19), range(19, 21)] in py3

كود:

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

وهيه، الإصدار سطر واحد

In [48]: chunk = lambda ulist, step:  map(lambda i: ulist[i:i+step],  xrange(0, len(ulist), step))

In [49]: chunk(range(1,100), 10)
Out[49]: 
[[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, 75, 76, 77, 78, 79, 80],
 [81, 82, 83, 84, 85, 86, 87, 88, 89, 90],
 [91, 92, 93, 94, 95, 96, 97, 98, 99]]
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

ونسخة أكثر وضوحا آخر.

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

وبدون ان تدعو ليون () وهو امر جيد للقوائم كبيرة:

def splitter(l, n):
    i = 0
    chunk = l[:n]
    while chunk:
        yield chunk
        i += n
        chunk = l[i:i+n]

وهذا هو لiterables:

def isplitter(l, n):
    l = iter(l)
    chunk = list(islice(l, n))
    while chunk:
        yield chunk
        chunk = list(islice(l, n))

ونكهة الوظيفية للأعلاه:

def isplitter2(l, n):
    return takewhile(bool,
                     (tuple(islice(start, n))
                            for start in repeat(iter(l))))

وOR:

def chunks_gen_sentinel(n, seq):
    continuous_slices = imap(islice, repeat(iter(seq)), repeat(0), repeat(n))
    return iter(imap(tuple, continuous_slices).next,())

وOR:

def chunks_gen_filter(n, seq):
    continuous_slices = imap(islice, repeat(iter(seq)), repeat(0), repeat(n))
    return takewhile(bool,imap(tuple, continuous_slices))

وحل واحد أكثر

def make_chunks(data, chunk_size): 
    while data:
        chunk, data = data[:chunk_size], data[chunk_size:]
        yield chunk

>>> for chunk in make_chunks([1, 2, 3, 4, 5, 6, 7], 2):
...     print chunk
... 
[1, 2]
[3, 4]
[5, 6]
[7]
>>> 

matplotlib.cbook قطع

وعلى سبيل المثال:

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

هذا المرجع

>>> orange = range(1, 1001)
>>> otuples = list( zip(*[iter(orange)]*10))
>>> print(otuples)
[(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), ... (991, 992, 993, 994, 995, 996, 997, 998, 999, 1000)]
>>> olist = [list(i) for i in otuples]
>>> print(olist)
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ..., [991, 992, 993, 994, 995, 996, 997, 998, 999, 1000]]
>>> 

وPython3

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

وعند هذه النقطة، وأعتقد أننا بحاجة إلى وظيفة غير معروفة، العودية إلزامية.

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

ومنذ الجميع هنا يتحدث عن التكرارات. boltons ديه طريقة مثالية لهذا، ودعا <لأ href = "https://boltons.readthedocs.io/en /latest/iterutils.html#boltons.iterutils.chunked_iter "يختلط =" noreferrer "> iterutils.chunked_iter .

from boltons import iterutils

list(iterutils.chunked_iter(list(range(50)), 11))

وإخراج:

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

ولكن إذا كنت لا تريد أن تكون رحمة على الذاكرة، يمكنك استخدام الطريقة القديمة-وتخزين list بالكامل في المقام الأول مع <لأ href = "https://boltons.readthedocs.io/en/latest /iterutils.html#boltons.iterutils.chunked "يختلط =" noreferrer "> iterutils.chunked .

فيما يلي قائمة بالطرق الإضافية:

منح

import itertools as it
import collections as ct

import more_itertools as mit


iterable = range(11)
n = 3

شفرة

المكتبة القياسية

list(it.zip_longest(*[iter(iterable)] * n))
# [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, None)]

d = {}
for i, x in enumerate(iterable):
    d.setdefault(i//n, []).append(x)

list(d.values())
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]

dd = ct.defaultdict(list)
for i, x in enumerate(iterable):
    dd[i//n].append(x)

list(dd.values())
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]

more_itertools+

list(mit.chunked(iterable, n))
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]

list(mit.sliced(iterable, n))
# [range(0, 3), range(3, 6), range(6, 9), range(9, 11)]

list(mit.grouper(n, iterable))
# [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, None)]

list(mit.windowed(iterable, len(iterable)//n, step=n))
# [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, None)]

مراجع

+ مكتبة خارجية تقوم بتنفيذ وصفات itertools و اكثر. > pip install more_itertools

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top