1

I need to be able to split an integer into a list of n-length evenly.

For example n = 4,

12 -> [0, 0, 1, 2]
1234 -> [1, 2, 3, 4]
12345 -> [1, 2, 3, 45]
123456 -> [1, 2, 34, 56]
1234567 -> [1, 23, 45, 67]
12345678 -> 12, 34, 56, 78]
123456789 -> [12, 34, 56, 789]

I'm sure I went overkill with the number of examples I have given, but it'll help get the point across.

The code that I have used in the past to split items into lists is:

def split(s, chunk_size):
    a = zip(*[s[i::chunk_size] for i in range(chunk_size)])
    return [''.join(t) for t in a]

but this code only breaks into n-chunks. (Code from StackOverflow, I don't remember the exact post, sorry).

Thanks for the help.

AustinB
  • 13
  • 3

4 Answers4

4
def split(seq, n):
    """Partitions `seq` into `n` successive slices of roughly equal size.

    The sizes of each yielded slice shall differ by at most one.
    """
    q, r = divmod(len(seq), n)
    start = 0

    for i in range(n):
        size = q + (i < r)
        yield seq[start : start + size]
        start += size

It basically works the same way as this popular answer, except it evenly distributes the remainder into each of the n slices.

Unfortunately, this will distribute towards the head of the list. To tweak it for your case, you need to change size = q + (i < r) to something like:

size = q + (i >= (n - r))

With this change, the following:

print(list(split('1234', 4)))
print(list(split('12345', 4)))
print(list(split('123456', 4)))
print(list(split('1234567', 4)))
print(list(split('12345678', 4)))
print(list(split('123456789', 4)))

prints:

['1', '2', '3', '4']
['1', '2', '3', '45']
['1', '2', '34', '56']
['1', '23', '45', '67']
['12', '34', '56', '78']
['12', '34', '56', '789']
Community
  • 1
  • 1
  • When I use the function and copied the prints I get this as my results: ['1', '2', '3', '4'], ['12', '3', '4', '5'], ['12', '34', '5', '6'], ['12', '34', '56', '7'], ['12', '34', '56', '78'], ['123', '45', '67', '89']. – AustinB Aug 25 '16 at 05:12
  • 1
    @AustinB Please read the answer in full before just copy+pasting. –  Aug 25 '16 at 05:14
  • Ah thanks, I am quite tired right now and just needed to quickly finish a portion of my project. Thanks for the help. – AustinB Aug 25 '16 at 05:19
  • [This](http://stackoverflow.com/q/2659900/6732794) older, more popular, similar question was brought to my attention just recently. In particular, this answer here is more or less the same in spirit as [this answer](http://stackoverflow.com/a/2660138/6732794) in the linked question. –  Nov 30 '16 at 20:20
0

Variant on Ahsan's answer that should distribute to the remainder across the end of the sequence correctly:

from itertools import accumulate

def split(s, parts):
    s = str(s)
    r, rem = divmod(len(s), parts)
    norem = parts - rem
    counts = [r]*norem + [r+1]*rem
    # Prepend 0 to counts only for accumulate to start from 0
    return [s[start:start+cnt] for start, cnt in zip(accumulate([0] + counts), counts)]
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
0

The selected answer has its advantage, but I did it in a more straightforward way:

def chunk(s, n):
    return [s[i:i+n] for i in range(0, len(s), n)]

def split(s0, numberOfChunks):
    s = ('0' * max(0, numberOfChunks - len(s0))) + s0
    sizeOfChunk = len(s) / numberOfChunks
    numberOfSmallChunks = numberOfChunks - len(s) % numberOfChunks
    return chunk(s[:numberOfSmallChunks * sizeOfChunk], sizeOfChunk) +
           chunk(s[sizeOfChunk*numberOfSmallChunks:], sizeOfChunk+1)
Michael Lorton
  • 43,060
  • 26
  • 103
  • 144
-1

sorry - for faulty code It is working according to the spec

def split(s, list_size):
    s = str(s)
    assert len(s) >= list_size, "assertion failed"
    r, rem = divmod(len(s), list_size)
    lst = []
    for i in range(list_size):
        lst.append(s[i*r:(i+1)*r])
    for j in range(rem):
        lst[-(j+1)] += s[list_size + j]
    return lst
Ahsan Habib
  • 174
  • 2
  • 5
  • This will fail with `1234567` case. – Selcuk Aug 25 '16 at 05:07
  • That shoves the entire remainder into the final element, does it not? The examples show that the remainder spread out; 7 items split 4 ways produces elements of length 1, 2, 2, 2, not 1, 1, 1, 4. – ShadowRanger Aug 25 '16 at 05:09
  • Now the bug has been fixed – Ahsan Habib Aug 25 '16 at 05:16
  • Getting an odd amount of 4's being produced into the lists, and numbers seem to be getting "shuffled": ['1', '2', '3', '4'] ['1', '2', '3', '44'] ['1', '2', '35', '44'] ['1', '26', '35', '44'] ['12', '34', '56', '78'] ['12', '34', '56', '784'] – AustinB Aug 25 '16 at 05:17