632

How do I split a string every nth character?

'1234567890'   →   ['12', '34', '56', '78', '90']

For the same question with a list, see How do I split a list into equally-sized chunks?.

0

21 Answers 21

815
>>> line = '1234567890'
>>> n = 2
>>> [line[i:i+n] for i in range(0, len(line), n)]
['12', '34', '56', '78', '90']
Sign up to request clarification or add additional context in comments.

5 Comments

@TrevorRudolph It only does exactly what you tell it. The above answer is really only just a for loop but expressed pythonically. Also, if you need to remember a "simplistic" answer, there are at least hundreds of thousands of ways to remember them: starring the page on stackoverflow; copying and then pasting into an email; keeping a "helpful" file with stuff you want to remember; simply using a modern search engine whenever you need something; using bookmarks in (probably) every web browser; etc.
It is easier to understand but it has the downside that you must reference 'line' twice.
Great for breaking up long lines for printing, e.g. for i in range(0, len(string), n): print(string[i:i+n])
for any noobs like me who don't get list comprehensions, the following may be easier to understand, in place of the last line: substrings = [] for i in range(0, len(line), n): substring = line[i:i+n] substrings.append(substring)
is there a way to do this while retaining line breaks? I'm trying to use this on a multiline string, it eats \ns and replaces them with spaces when I join them together
359

Just to be complete, you can do this with a regex:

>>> import re
>>> re.findall('..','1234567890')
['12', '34', '56', '78', '90']

For odd number of chars you can do this:

>>> import re
>>> re.findall('..?', '123456789')
['12', '34', '56', '78', '9']

You can also do the following, to simplify the regex for longer chunks:

>>> import re
>>> re.findall('.{1,2}', '123456789')
['12', '34', '56', '78', '9']

And you can use re.finditer if the string is long to generate chunk by chunk.

5 Comments

This is by far the best answer here and deserves to be on top. One could even write '.'*n to make it more clear. No joining, no zipping, no loops, no list comprehension; just find the next two characters next to each other, which is exactly how a human brain thinks about it. If Monty Python were still alive, he'd love this method!
This is the fastest method for reasonably long strings too: gitlab.com/snippets/1908857
This won't work if the string contains newlines. This needs flags=re.S.
Yeah this is not a good answer. Regexes have so many gotchas (as Aran-Fey found!) that you should use them very sparingly. You definitely don't need them here. They're only faster because they're implemented in C and Python is crazy slow.
This is fast but more_itertools.sliced seems more efficient.
322

There is already an inbuilt function in Python for this.

>>> from textwrap import wrap
>>> s = '1234567890'
>>> wrap(s, 2)
['12', '34', '56', '78', '90']

This is what the docstring for wrap says:

>>> help(wrap)
'''
Help on function wrap in module textwrap:

wrap(text, width=70, **kwargs)
    Wrap a single paragraph of text, returning a list of wrapped lines.

    Reformat the single paragraph in 'text' so it fits in lines of no
    more than 'width' columns, and return a list of wrapped lines.  By
    default, tabs in 'text' are expanded with string.expandtabs(), and
    all other whitespace characters (including newline) are converted to
    space.  See TextWrapper class for available keyword args to customize
    wrapping behaviour.
'''

9 Comments

print(wrap('12345678', 3)) splits the string into groups of 3 digits, but starts in front and not behind. Result: ['123', '456', '78']
It is interesting to learn about 'wrap' yet it is not doing exactly what was asked above. It is more oriented towards displaying text, rather than splitting a string to a fixed number of characters.
wrap may not return what is asked for if the string contains space. e.g. wrap('0 1 2 3 4 5', 2) returns ['0', '1', '2', '3', '4', '5'] (the elements are stripped)
This indeed answers the question, but what happens if there's spaces and you want them maintained in the split characters? wrap() removes spaces if they fall straight after a split group of characters
This works poorly if you want to split text with hyphens (the number you give as argument is actually the MAXIMUM number of characters, not exact one, and it breaks i.e. on hyphens and white spaces).
|
102

Another common way of grouping elements into n-length groups:

>>> s = '1234567890'
>>> map(''.join, zip(*[iter(s)]*2))
['12', '34', '56', '78', '90']

This method comes straight from the docs for zip().

6 Comments

In [19]: a = "hello world"; list( map( "".join, zip(*[iter(a)]*4) ) ) get the result ['hell', 'o wo'].
If someone finds zip(*[iter(s)]*2) tricky to understand, read How does zip(*[iter(s)]*n) work in Python?.
This does not account for an odd number of chars, it'll simply drop those chars: >>> map(''.join, zip(*[iter('01234567')]*5)) -> ['01234']
To also handle odd number of chars just replace zip() with itertools.zip_longest(): map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
I hope I never find this in production. Incredibly difficult to read for something that should be rather simple
|
77

I think this is shorter and more readable than the itertools version:

def split_by_n(seq, n):
    '''A generator to divide a sequence into chunks of n units.'''
    while seq:
        yield seq[:n]
        seq = seq[n:]

print(list(split_by_n('1234567890', 2)))

2 Comments

but not really efficient: when applied to strings: too many copies
It also doesn't work if seq is a generator, which is what the itertools version is for. Not that OP asked for that, but it's not fair to criticize itertool's version not being as simple.
44

Using more-itertools from PyPI:

>>> from more_itertools import sliced
>>> list(sliced('1234567890', 2))
['12', '34', '56', '78', '90']

Comments

37

I like this solution:

s = '1234567890'
o = []
while s:
    o.append(s[:2])
    s = s[2:]

1 Comment

for loops are faster in python especially if you are iterating many times
19

You could use the grouper() recipe from itertools:

Python 2.x:

from itertools import izip_longest    

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

Python 3.x:

from itertools import zip_longest

def grouper(iterable, n, *, incomplete='fill', fillvalue=None):
    "Collect data into non-overlapping fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, fillvalue='x') --> ABC DEF Gxx
    # grouper('ABCDEFG', 3, incomplete='strict') --> ABC DEF ValueError
    # grouper('ABCDEFG', 3, incomplete='ignore') --> ABC DEF
    args = [iter(iterable)] * n
    if incomplete == 'fill':
        return zip_longest(*args, fillvalue=fillvalue)
    if incomplete == 'strict':
        return zip(*args, strict=True)
    if incomplete == 'ignore':
        return zip(*args)
    else:
        raise ValueError('Expected fill, strict, or ignore')

These functions are memory-efficient and work with any iterables.

2 Comments

Throwing an overflow when using very large strings (len=2**22*40)
@FifthAxiom What version of Python and what kind of overflow are you talking about?
17

This can be achieved by a simple for loop.

a = '1234567890a'
result = []

for i in range(0, len(a), 2):
    result.append(a[i : i + 2])
print(result)

The output looks like ['12', '34', '56', '78', '90', 'a']

3 Comments

While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.
This is the same solution as here: stackoverflow.com/a/59091507/7851470
This is the same solution as the top voted answer - except for the fact that the top answer is using list comprehension.
15

I was stuck in the same scenario.

This worked for me:

x = "1234567890"
n = 2
my_list = []
for i in range(0, len(x), n):
    my_list.append(x[i:i+n])
print(my_list)

Output:

['12', '34', '56', '78', '90']

1 Comment

Wondering why this is not more upvoted? Guessing I am missing some concept. I like the answer because we don't import anything else and it seemed like the most obvious solution. I did find some "weird" results with the following string (n=2): 'testt\n\n\\\\zz' ... results in: ['te', 'st', 't\n', '\n\\', '\\z', 'z']
12

Try this:

s = '1234567890'
print([s[idx:idx+2] for idx in range(len(s)) if idx % 2 == 0])

Output:

['12', '34', '56', '78', '90']

1 Comment

why enumerate(s) if you're going to ignore the val? just do for i in range(len(s)); why iterate over every value only to throw away half of them? just skip the values you don't need: for i in range(0, len(s), 2) (and skip the if part)
9

Try the following code:

from itertools import islice

def split_every(n, iterable):
    i = iter(iterable)
    piece = list(islice(i, n))
    while piece:
        yield piece
        piece = list(islice(i, n))

s = '1234567890'
print list(split_every(2, list(s)))

1 Comment

Your answer doesn't meet OP's requirement, you have to use yield ''.join(piece) to make it work as expected: eval.in/813878
7

As always, for those who love one liners:

n = 2  
line = "this is a line split into n characters"  
split = [line[i:i+n] for i in range(0,len(line),n)]

7 Comments

When I run this in Python Fiddle with a print(line) I get this is a line split into n characters as the output. Might you be better putting: line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]? Fix this and it's a good answer :).
Can you explain the ,blah and why it's necessary? I notice I can replace blah with any alpha character/s, but not numbers, and can't remove the blah or/and the comma. My editor suggests adding whitespace after , :s
enumerate returns two iterables, so you need two places to put them. But you don't actually need the second iterable for anything in this case.
Rather than blah I prefer to use an underscore or double underscore, see: stackoverflow.com/questions/5893163/…
Why not range(len(line[::n])) instead of enumerate(…) that way, or better yet range(len(range(0,len(line),n)))?
|
6
>>> from functools import reduce
>>> from operator import add
>>> from itertools import izip
>>> x = iter('1234567890')
>>> [reduce(add, tup) for tup in izip(x, x)]
['12', '34', '56', '78', '90']
>>> x = iter('1234567890')
>>> [reduce(add, tup) for tup in izip(x, x, x)]
['123', '456', '789']

Comments

5

As of Python 3.12, the itertools libray now includes the iterator, batched().

>>> from itertools import batched
>>> s = '1234567890'
>>> [''.join(batch) for batch in batched(s, 2)]
['12', '34', '56', '78', '90']

Comments

3

more_itertools.sliced has been mentioned before. Here are four more options from the more_itertools library:

s = "1234567890"

["".join(c) for c in mit.grouper(2, s)]

["".join(c) for c in mit.chunked(s, 2)]

["".join(c) for c in mit.windowed(s, 2, step=2)]

["".join(c) for c in  mit.split_after(s, lambda x: int(x) % 2 == 0)]

Each of the latter options produce the following output:

['12', '34', '56', '78', '90']

Documentation for discussed options: grouper, chunked, windowed, split_after

Comments

3

A simple recursive solution for short string:

def split(s, n):
    if len(s) < n:
        return []
    else:
        return [s[:n]] + split(s[n:], n)

print(split('1234567890', 2))

Or in such a form:

def split(s, n):
    if len(s) < n:
        return []
    elif len(s) == n:
        return [s]
    else:
        return split(s[:n], n) + split(s[n:], n)

, which illustrates the typical divide and conquer pattern in recursive approach more explicitly (though practically it is not necessary to do it this way)

Comments

3

A solution with groupby:

from itertools import groupby, chain, repeat, cycle

text = "wwworldggggreattecchemggpwwwzaz"
n = 3
c = cycle(chain(repeat(0, n), repeat(1, n)))
res = ["".join(g) for _, g in groupby(text, lambda x: next(c))]
print(res)

Output:

['www', 'orl', 'dgg', 'ggr', 'eat', 'tec', 'che', 'mgg', 'pww', 'wza', 'z']

Comments

1

Edit: The code below is incorrect. The correct version is:

from itertools import groupby

text = "abcdefghij"
n = 3

result = []
for idx, chunk in groupby(enumerate(text), key=lambda x: x[0]//n):
    result.append("".join(char for _, char in chunk))

But it's still unnecessarily complicated.


Another solution using groupby and index//n as the key to group the letters:

from itertools import groupby

text = "abcdefghij"
n = 3

result = []
for idx, chunk in groupby(text, key=lambda x: x.index//n):
    result.append("".join(chunk))

# result = ['abc', 'def', 'ghi', 'j']

2 Comments

What do you think x.index means here?
I edited my answer. My code was incorrect. Thank you for pointing it out.
0

These answers are all nice and working and all, but the syntax is so cryptic... Why not write a simple function?

def SplitEvery(string, length):
    if len(string) <= length: return [string]        
    sections = len(string) / length
    lines = []
    start = 0;
    for i in range(sections):
        line = string[start:start+length]
        lines.append(line)
        start += length
    return lines

And call it simply:

text = '1234567890'
lines = SplitEvery(text, 2)
print(lines)

# output: ['12', '34', '56', '78', '90']

2 Comments

You cannot pass a float to the range function, so the function you display wouldn't work. (Try running it if you don't believe me)
Debugging (or verifying the correctness of) this function is rather harder than debugging something that isn't so redundant. It also requires allocating the entire return value all at once (which the list comprehension answer can more easily be adapted to avoid).
-2

A full write-up with updated solutions can be found here on Github.

NOTE: Solutions are written for Python3.10+

Using List Comprehension and Slicing: This is a simple and straightforward approach where we can use Python’s slicing feature to split the string into chunks of n characters. We can use list comprehension to iterate over the string with a step size of n and slice the string from the current index to the current index plus n.

def split_string_into_groups(s: str, n: int) -> list[str]:
    """
    Splits a string into groups of `n` consecutive characters.

    This function uses list comprehension and slicing to split the string into groups.
    It includes error handling to check if `n` is a positive integer.

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        list[str]: A list of strings, where each string is a group of `n` consecutive characters from the input string.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> split_string_into_groups("HelloWorld", 3)
        ['Hel', 'loW', 'orl', 'd']
        >>> split_string_into_groups("Python", 2)
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Use list comprehension and slicing to split the string into groups of `n` characters.
    return [s[i:i + n] for i in range(0, len(s), n)]

Using the re (regex) Module: Python’s re module provides a function called findall(), which can be used to find all occurrences of a pattern in a string. We can use this function with a regular expression that matches any n characters to split the string into chunks of n characters.

import re

def split_string_into_groups(s: str, n: int) -> list[str]:
    """
    Splits a string into groups of `n` consecutive characters.

    This function uses the `re.findall()` function from the `re` (regex) module to solve the problem.
    It includes error handling to check if `n` is a positive integer.

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        list[str]: A list of strings, where each string is a group of `n` consecutive characters from the input string.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> split_string_into_groups("HelloWorld", 3)
        ['Hel', 'loW', 'orl', 'd']
        >>> split_string_into_groups("Python", 2)
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Use `re.findall()` to split the string into groups of `n` characters.
    return re.findall(f'.{{1,{n}}}', s)

Using the textwrap Module: The textwrap module in Python provides a function called wrap(), which can be used to split a string into a list of output lines of specified width. We can use this function to split the string into chunks of n characters.

import textwrap

def split_string_into_groups(s: str, n: int) -> list[str]:
    """
    Splits a string into groups of `n` consecutive characters.

    This function uses the `textwrap.wrap()` function from the `textwrap` module to solve the problem.
    It includes error handling to check if `n` is a positive integer.

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        List[str]: A list of strings, where each string is a group of `n` consecutive characters from the input string.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> split_string_into_groups("HelloWorld", 3)
        ['Hel', 'loW', 'orl', 'd']
        >>> split_string_into_groups("Python", 2)
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Use `textwrap.wrap()` to split the string into groups of `n` characters.
    return textwrap.wrap(s, n)

Using a Loop and String Concatenation: We can also solve this problem by manually looping over the string and concatenating n characters at a time to a new string. Once we have n characters, we can add the new string to a list and reset the new string to an empty string.

def split_string_into_groups(s: str, n: int) -> list[str]:
    """
    Splits a string into groups of `n` consecutive characters.

    This function uses a loop and string concatenation to solve the problem.
    It includes error handling to check if `n` is a positive integer.

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        List[str]: A list of strings, where each string is a group of `n` consecutive characters from the input string.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> split_string_into_groups("HelloWorld", 3)
        ['Hel', 'loW', 'orl', 'd']
        >>> split_string_into_groups("Python", 2)
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Initialize an empty list to store the groups.
    result = []

    # Initialize an empty string to store the current group.
    group = ''

    # Iterate over each character in the string.
    for c in s:
        group += c  # Add the current character to the current group.

        # If the current group has `n` characters, add it to the result and reset the group.
        if len(group) == n:
            result.append(group)
            group = ''

    # If there are any remaining characters in the group, add it to the result.
    if group:
        result.append(group)

    return result

Using Generator Function: We can create a generator function that takes a string and a number n as input and yields chunks of n characters from the string. This approach is memory efficient as it doesn’t require storing all chunks in memory at once.

from typing import Generator


def split_string_into_groups(string: str, n: int) -> Generator[str, None, None]:
    """
    Generator function to split a string into groups of `n` consecutive characters.

    Args:
        string (str): The input string to be split.
        n (int): The size of the groups.

    Yields:
        str: The next group of `n` characters.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> list(split_string_into_groups("HelloWorld", 3))
        ['Hel', 'loW', 'orl', 'd']
        >>> list(split_string_into_groups("Python", 2))
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Iterate over the string with a step size of `n`.
    for i in range(0, len(string), n):
        # Yield the next group of `n` characters.
        yield string[i:i + n]

Using itertools: The itertools module in Python provides a function called islice(), which can be used to slice an iterable. We can use this function to split the string into chunks of n characters.

from itertools import islice
from typing import Iterator


def split_string_into_groups(s: str, n: int) -> Iterator[str]:
    """
    Splits a string into groups of `n` consecutive characters using itertools.islice().

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        Iterator[str]: An iterator that yields each group of `n` consecutive characters from the input string.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> list(split_string_into_groups("HelloWorld", 3))
        ['Hel', 'loW', 'orl', 'd']
        >>> list(split_string_into_groups("Python", 2))
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Create an iterator from the string.
    it = iter(s)

    # Use itertools.islice() to yield groups of `n` characters from the iterator.
    while True:
        group = ''.join(islice(it, n))

        if not group:
            break

        yield group

Using numpy: We can also use the numpy library to solve this problem. We can convert the string to a numpy array and then use the reshape() function to split the array into chunks of n characters.

import numpy as np


def split_string_into_groups(s: str, n: int) -> list[str]:
    """
    Splits a string into groups of `n` consecutive characters using numpy.reshape().

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        List[str]: A list of strings where each string is a group of `n` consecutive characters.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> split_string_into_groups("HelloWorld", 3)
        ['Hel', 'loW', 'orl', 'd']
        >>> split_string_into_groups("Python", 2)
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Convert the string to a list of characters
    chars = list(s)

    # Add extra empty strings only if the length of `s` is not a multiple of `n`
    if len(s) % n != 0:
        chars += [''] * (n - len(s) % n)

    # Reshape the array into a 2D array with the number of groups as the number of rows and n as the number of columns
    arr = np.array(chars).reshape(-1, n)

    # Convert each row of the 2D array back to a string and add it to the result list
    result = [''.join(row).rstrip() for row in arr]

    return result

Using pandas: The pandas library in Python provides a function called groupby(), which can be used to split an array into bins. We can use this function to split the string into chunks of n characters.

import pandas as pd


def split_string_into_groups(s: str, n: int) -> list[str]:
    """
    Splits a given string into groups of `n` consecutive characters.

    This function uses the pandas library to convert the string into a pandas Series,
    then uses the groupby method to group the characters into groups of `n` characters.
    The groups are then converted back to a list of strings.

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        list[str]: A list of strings, where each string is a group of `n` consecutive characters from the input string.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> split_string_into_groups("HelloWorld", 3)
        ['Hel', 'loW', 'orl', 'd']
        >>> split_string_into_groups("Python", 2)
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Convert the string to a pandas Series
    s = pd.Series(list(s))

    # Use pandas groupby to group the characters
    # The index of each character is divided by `n` using integer division,
    # which groups the characters into groups of `n` characters.
    groups = s.groupby(s.index // n).agg(''.join)

    # Convert the result back to a list and return it
    return groups.tolist()

Using more_itertools: The more_itertools library provides a function called chunked(), which can be used to split an iterable into chunks of a specified size. We can use this function to split the string into chunks of n characters.

import more_itertools


def split_string_into_groups(s: str, n: int) -> list[str]:
    """
    Splits a string into groups of `n` consecutive characters using more_itertools.chunked().

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        List[str]: A list of strings where each string is a group of `n` consecutive characters.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> split_string_into_groups("HelloWorld", 3)
        ['Hel', 'loW', 'orl', 'd']
        >>> split_string_into_groups("Python", 2)
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Use more_itertools.chunked() to split the string into chunks of `n` characters.
    chunks = more_itertools.chunked(s, n)

    # Convert each chunk to a string and add it to the result list.
    result = [''.join(chunk) for chunk in chunks]

    return result

Using toolz: The toolz library provides a function called partition_all(), which can be used to split an iterable into chunks of a specified size. We can use this function to split the string into chunks of n characters.

import toolz


def split_string_into_groups(s: str, n: int) -> list[str]:
    """
    Splits a string into groups of `n` consecutive characters using toolz.partition_all().

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        List[str]: A list of strings where each string is a group of `n` consecutive characters.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> split_string_into_groups("HelloWorld", 3)
        ['Hel', 'loW', 'orl', 'd']
        >>> split_string_into_groups("Python", 2)
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Use toolz.partition_all() to split the string into chunks of `n` characters.
    chunks = toolz.partition_all(n, s)

    # Convert each chunk to a string and add it to the result list.
    result = [''.join(chunk) for chunk in chunks]

    return result

Using cytoolz: The cytoolz library provides a function called partition_all(), which can be used to split an iterable into chunks of a specified size. We can use this function to split the string into chunks of n characters.

from cytoolz import partition_all


def split_string_into_groups(s: str, n: int) -> list[str]:
    """
    Splits a string into groups of `n` consecutive characters using cytoolz.partition_all().

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        list[str]: A list of strings where each string is a group of `n` consecutive characters.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> split_string_into_groups("HelloWorld", 3)
        ['Hel', 'loW', 'orl', 'd']
        >>> split_string_into_groups("Python", 2)
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Use cytoolz.partition_all() to split the string into chunks of `n` characters.
    chunks = partition_all(n, s)

    # Convert each chunk to a string and add it to the result list.
    result = [''.join(chunk) for chunk in chunks]

    return result

Using itertools: The itertools library provides a function called zip_longest, which can be used to split an iterable into chunks of a specified size. We can use this function to split the string into chunks of n characters.

from itertools import zip_longest


def split_string_into_groups(s: str, n: int) -> list[str]:
    """
    Splits a string into groups of `n` consecutive characters using itertools.zip_longest().

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        List[str]: A list of strings where each string is a group of `n` consecutive characters.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> split_string_into_groups("HelloWorld", 3)
        ['Hel', 'loW', 'orl', 'd']
        >>> split_string_into_groups("Python", 2)
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Use itertools.zip_longest() to split the string into chunks of `n` characters.
    args = [iter(s)] * n
    chunks = zip_longest(*args, fillvalue='')

    # Convert each chunk to a string and add it to the result list.
    result = [''.join(chunk) for chunk in chunks]

    return result

Using list + map + join + zip: We can also solve this problem using the list function, the map function, the join method, and the zip function. We can use the map function to iterate over the string with a step size of n and slice the string from the current index to the current index plus n. We can then use the zip function to combine the chunks into a list of tuples, and the join method to join the tuples into a list of strings.

def split_string_into_groups(s: str, n: int) -> list[str]:
    """
    Splits a string into groups of `n` consecutive characters using list, map, join, and zip.

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        list[str]: A list of strings where each string is a group of `n` consecutive characters.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> split_string_into_groups("HelloWorld", 3)
        ['Hel', 'loW', 'orl', 'd']
        >>> split_string_into_groups("Python", 2)
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Use list, map, join, and zip to split the string into chunks of `n` characters.
    result = [''.join(chunk) for chunk in zip(*[iter(s)] * n)]

    # If the string length is not a multiple of `n`, add the remaining characters to the result.
    remainder = len(s) % n
    if remainder != 0:
        result.append(s[-remainder:])

    return result

Using Recursion with Slicing: We can also solve this problem using recursion and slicing. We can define a recursive function that takes a string and a number n as input and returns a list of chunks of n characters. The function can slice the string into chunks of n characters and call itself recursively with the remaining string until the string is empty.

def split_string_into_groups(s: str, n: int) -> list[str]:
    """
    Splits a string into groups of `n` consecutive characters using recursion with slicing.

    Args:
        s (str): The input string to be split.
        n (int): The size of the groups.

    Returns:
        list[str]: A list of strings where each string is a group of `n` consecutive characters.

    Raises:
        ValueError: If `n` is not a positive integer.

    Examples:
        >>> split_string_into_groups("HelloWorld", 3)
        ['Hel', 'loW', 'orl', 'd']
        >>> split_string_into_groups("Python", 2)
        ['Py', 'th', 'on']
    """
    # Check if `n` is a positive integer.
    if n <= 0:
        raise ValueError("The group size must be a positive integer")

    # Base case: if the length of the string is less than or equal to `n`, return a list containing `s`.
    if len(s) <= n:
        return [s]

    # Recursive case: split the string into two parts and recursively call `split_string_into_groups` on the rest of the string.
    return [s[:n]] + split_string_into_groups(s[n:], n)

2 Comments

did you really need to copy the same docstring examples section for every single one?
They just happened to be the same. Sometimes different solutions to the same problem require different examples as they work slightly differently. e.g. Some solutions might preserve order while others don't. As a learning tool it is helpful to have all documentation available at each location instead of saying hey for doc-tests see this solution over here. Also, the source code is built into a project as separate files. You likely wouldn't notice if looking at them all separately.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.