201

リストをほぼ等しい部分に分割する最良の方法は何ですか? たとえば、リストに 7 つの要素があり、2 つの部分に分割されている場合、1 つの部分に 3 つの要素を取得し、もう 1 つの部分には 4 つの要素を含める必要があります。

バラバラにeven_split(L, n)分解できるようなものを探しています。Ln

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

上記のコードは、3 つのチャンクではなく、3 つのチャンクを提供します。単純に転置することはできますが (これを反復して各列の最初の要素を取得し、その部分を 1 と呼び、2 番目を取得して部分 2 に入れるなど)、項目の順序が崩れてしまいます。

4

34 に答える 34

262

リストジェネレータとしてかなり簡単に書くことができます:

def split(a, n):
    k, m = divmod(len(a), n)
    return (a[i*k+min(i, m):(i+1)*k+min(i+1, m)] for i in range(n))

例:

>>> list(split(range(11), 3))
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10]]
于 2010-01-25T21:48:42.980 に答える
227

これが*の存在理由です。numpy.array_split

>>> import numpy as np
>>> print(*np.array_split(range(10), 3))
[0 1 2 3] [4 5 6] [7 8 9]
>>> print(*np.array_split(range(10), 4))
[0 1 2] [3 4 5] [6 7] [8 9]
>>> print(*np.array_split(range(10), 5))
[0 1] [2 3] [4 5] [6 7] [8 9]

*部屋6のZero Piraeusへのクレジット

于 2017-03-30T00:22:34.813 に答える
127

連続チャンクのようなばかげたものを望まない限り:

>>> def chunkify(lst,n):
...     return [lst[i::n] for i in xrange(n)]
... 
>>> chunkify(range(13), 3)
[[0, 3, 6, 9, 12], [1, 4, 7, 10], [2, 5, 8, 11]]
于 2010-01-25T22:18:16.597 に答える
80

このコードは、丸め誤差のために壊れています。使用しないでください!!!

assert len(chunkIt([1,2,3], 10)) == 10  # fails

これがうまくいくものです:

def chunkIt(seq, num):
    avg = len(seq) / float(num)
    out = []
    last = 0.0

    while last < len(seq):
        out.append(seq[int(last):int(last + avg)])
        last += avg

    return out

テスト:

>>> chunkIt(range(10), 3)
[[0, 1, 2], [3, 4, 5], [6, 7, 8, 9]]
>>> chunkIt(range(11), 3)
[[0, 1, 2], [3, 4, 5, 6], [7, 8, 9, 10]]
>>> chunkIt(range(12), 3)
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
于 2010-01-25T03:27:31.450 に答える
20

nのチャンクではなくチャンクを生成するようにコードを変更しますn

def chunks(l, n):
    """ Yield n successive chunks from l.
    """
    newn = int(len(l) / n)
    for i in xrange(0, n-1):
        yield l[i*newn:i*newn+newn]
    yield l[n*newn-newn:]

l = range(56)
three_chunks = chunks (l, 3)
print three_chunks.next()
print three_chunks.next()
print three_chunks.next()

これは次を与えます:

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

これにより、余分な要素が最終グループに割り当てられますが、これは完全ではありませんが、「ほぼ N 等しい部分」の仕様の範囲内です :-) つまり、56 要素は (19,19,18) として優れていることを意味しますが、これは(18,18,20)。

次のコードを使用すると、よりバランスの取れた出力を得ることができます。

#!/usr/bin/python
def chunks(l, n):
    """ Yield n successive chunks from l.
    """
    newn = int(1.0 * len(l) / n + 0.5)
    for i in xrange(0, n-1):
        yield l[i*newn:i*newn+newn]
    yield l[n*newn-newn:]

l = range(56)
three_chunks = chunks (l, 3)
print three_chunks.next()
print three_chunks.next()
print three_chunks.next()

出力:

[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]
于 2010-01-25T03:30:11.397 に答える
20

n要素を大まかにkチャンクに分割するn % kと、チャンクを他のチャンクよりも 1 要素大きくして、余分な要素を分散させることができます。

次のコードは、チャンクの長さを示します。

[(n // k) + (1 if i < (n % k) else 0) for i in range(k)]

例:n=11, k=3結果[4, 4, 3]

その後、チャンクの開始インデックスを簡単に計算できます。

[i * (n // k) + min(i, n % k) for i in range(k)]

例:n=11, k=3結果[0, 4, 8]

i+1th チャンクを境界として使用すると、len を持つilist の th チャンクがln

l[i * (n // k) + min(i, n % k):(i+1) * (n // k) + min(i+1, n % k)]

最後のステップとして、リスト内包表記を使用してすべてのチャンクからリストを作成します。

[l[i * (n // k) + min(i, n % k):(i+1) * (n // k) + min(i+1, n % k)] for i in range(k)]

例:n=11, k=3, l=range(n)結果[range(0, 4), range(4, 8), range(8, 11)]

于 2016-05-24T12:48:57.627 に答える
6

numpy.splitを見てください:

>>> a = numpy.array([1,2,3,4])
>>> numpy.split(a, 2)
[array([1, 2]), array([3, 4])]
于 2010-02-10T09:19:37.890 に答える
6

Noneリストを同じ長さにするために追加するものを次に示します

>>> from itertools import izip_longest
>>> def chunks(l, n):
    """ Yield n successive chunks from l. Pads extra spaces with None
    """
    return list(zip(*izip_longest(*[iter(l)]*n)))

>>> l=range(54)

>>> chunks(l,3)
[(0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51), (1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52), (2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53)]

>>> chunks(l,4)
[(0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52), (1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53), (2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, None), (3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, None)]

>>> chunks(l,5)
[(0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50), (1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51), (2, 7, 12, 17, 22, 27, 32, 37, 42, 47, 52), (3, 8, 13, 18, 23, 28, 33, 38, 43, 48, 53), (4, 9, 14, 19, 24, 29, 34, 39, 44, 49, None)]
于 2010-01-25T03:34:22.380 に答える
6

これは、任意の正数 (整数) のチャンクを処理できるジェネレーターです。チャンクの数が入力リストの長さよりも大きい場合、一部のチャンクは空になります。このアルゴリズムは、短いチャンクと長いチャンクを分離するのではなく、交互に切り替えます。

ragged_chunks関数をテストするためのコードもいくつか含めました。

''' Split a list into "ragged" chunks

    The size of each chunk is either the floor or ceiling of len(seq) / chunks

    chunks can be > len(seq), in which case there will be empty chunks

    Written by PM 2Ring 2017.03.30
'''

def ragged_chunks(seq, chunks):
    size = len(seq)
    start = 0
    for i in range(1, chunks + 1):
        stop = i * size // chunks
        yield seq[start:stop]
        start = stop

# test

def test_ragged_chunks(maxsize):
    for size in range(0, maxsize):
        seq = list(range(size))
        for chunks in range(1, size + 1):
            minwidth = size // chunks
            #ceiling division
            maxwidth = -(-size // chunks)
            a = list(ragged_chunks(seq, chunks))
            sizes = [len(u) for u in a]
            deltas = all(minwidth <= u <= maxwidth for u in sizes)
            assert all((sum(a, []) == seq, sum(sizes) == size, deltas))
    return True

if test_ragged_chunks(100):
    print('ok')

乗算を呼び出しにエクスポートすることで、これを少し効率的にすることができrangeますが、以前のバージョンの方が読みやすい (そして DRYer) と思います。

def ragged_chunks(seq, chunks):
    size = len(seq)
    start = 0
    for i in range(size, size * chunks + 1, size):
        stop = i // chunks
        yield seq[start:stop]
        start = stop
于 2017-03-30T09:51:35.660 に答える
5

これが私の解決策です:

def chunks(l, amount):
    if amount < 1:
        raise ValueError('amount must be positive integer')
    chunk_len = len(l) // amount
    leap_parts = len(l) % amount
    remainder = amount // 2  # make it symmetrical
    i = 0
    while i < len(l):
        remainder += leap_parts
        end_index = i + chunk_len
        if remainder >= amount:
            remainder -= amount
            end_index += 1
        yield l[i:end_index]
        i = end_index

プロデュース

    >>> list(chunks([1, 2, 3, 4, 5, 6, 7], 3))
    [[1, 2], [3, 4, 5], [6, 7]]
于 2014-09-24T15:55:54.993 に答える
4

リスト[1、2、3、4、5、6、7、8]を3つの要素リストに分割したいとしましょう

[[1,2,3], [4, 5, 6], [7, 8]]のように、最後に残った要素が 3 未満の場合、それらはグループ化されます。

my_list = [1, 2, 3, 4, 5, 6, 7, 8]
my_list2 = [my_list[i:i+3] for i in range(0, len(my_list), 3)]
print(my_list2)

出力: [[1,2,3], [4, 5, 6], [7, 8]]

1 つの部分の長さは 3 です。3 を独自のチャンク サイズに置き換えます。

于 2020-06-04T11:23:18.157 に答える
1

これは、「残りの」要素をすべてのチャンクに均等に、一度に 1 つずつ、何も残らなくなるまで分散させる別のバリ​​アントです。この実装では、プロセスの開始時に大きなチャンクが発生します。

def chunks(l, k):
  """ Yield k successive chunks from l."""
  if k < 1:
    yield []
    raise StopIteration
  n = len(l)
  avg = n/k
  remainders = n % k
  start, end = 0, avg
  while start < n:
    if remainders > 0:
      end = end + 1
      remainders = remainders - 1
    yield l[start:end]
    start, end = end, end+avg

たとえば、14 個の要素のリストから 4 つのチャンクを生成します。

>>> list(chunks(range(14), 4))
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10], [11, 12, 13]]
>>> map(len, list(chunks(range(14), 4)))
[4, 4, 3, 3]
于 2013-09-22T16:54:11.263 に答える
1

別の方法は次のようなものです。ここでのアイデアは、グルーパーを使用することですが、None. この場合、すべての「small_parts」はリストの最初の部分の要素から形成され、「larger_parts」はリストの後半の部分から形成されます。「大きいパーツ」の長さは len(small_parts) + 1 です。x を 2 つの異なるサブパーツと見なす必要があります。

from itertools import izip_longest

import numpy as np

def grouper(n, iterable, fillvalue=None): # This is grouper from itertools
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

def another_chunk(x,num):
    extra_ele = len(x)%num #gives number of parts that will have an extra element 
    small_part = int(np.floor(len(x)/num)) #gives number of elements in a small part

    new_x = list(grouper(small_part,x[:small_part*(num-extra_ele)]))
    new_x.extend(list(grouper(small_part+1,x[small_part*(num-extra_ele):])))

    return new_x

私がセットアップした方法は、タプルのリストを返します。

>>> x = range(14)
>>> another_chunk(x,3)
[(0, 1, 2, 3), (4, 5, 6, 7, 8), (9, 10, 11, 12, 13)]
>>> another_chunk(x,4)
[(0, 1, 2), (3, 4, 5), (6, 7, 8, 9), (10, 11, 12, 13)]
>>> another_chunk(x,5)
[(0, 1), (2, 3, 4), (5, 6, 7), (8, 9, 10), (11, 12, 13)]
>>> 
于 2012-03-21T04:05:55.490 に答える
1
#!/usr/bin/python


first_names = ['Steve', 'Jane', 'Sara', 'Mary','Jack','Bob', 'Bily', 'Boni', 'Chris','Sori', 'Will', 'Won','Li']

def chunks(l, n):
for i in range(0, len(l), n):
    # Create an index range for l of n items:
    yield l[i:i+n]

result = list(chunks(first_names, 5))
print result

このリンクから選択しましたが、これが私を助けてくれました。事前に定義されたリストがありました。

于 2018-09-05T04:28:24.717 に答える
1

仕事の答えと同じですが、チャンクの数よりも小さいサイズのリストを考慮に入れます。

def chunkify(lst,n):
    [ lst[i::n] for i in xrange(n if n < len(lst) else len(lst)) ]

n (チャンクの数) が 7 で、lst (分割するリスト) が [1, 2, 3] の場合、チャンクは [[0], [1] ではなく [[0], [1], [2]] になります。 ]、[2]、[]、[]、[]、[]]

于 2014-06-13T14:37:56.997 に答える
-1

linspace を丸め、それをインデックスとして使用することは、amit12690 が提案するよりも簡単なソリューションです。

function chunks=chunkit(array,num)

index = round(linspace(0,size(array,2),num+1));

chunks = cell(1,num);

for x = 1:num
chunks{x} = array(:,index(x)+1:index(x+1));
end
end
于 2016-07-20T13:04:20.813 に答える
-1

このコードは私のために機能します(Python3互換):

def chunkify(tab, num):
    return [tab[i*num: i*num+num] for i in range(len(tab)//num+(1 if len(tab)%num else 0))]

例 ( bytearray型の場合ですが、リストでも機能します):

b = bytearray(b'\x01\x02\x03\x04\x05\x06\x07\x08')
>>> chunkify(b,3)
[bytearray(b'\x01\x02\x03'), bytearray(b'\x04\x05\x06'), bytearray(b'\x07\x08')]
>>> chunkify(b,4)
[bytearray(b'\x01\x02\x03\x04'), bytearray(b'\x05\x06\x07\x08')]
于 2019-07-13T18:37:03.900 に答える