Is there any way to use the 'splat' operator (e.g. a, *rest = somelist) in such a way that it consumes a certain number of items?
Use case: I want to split some input I'm getting into a number, a list of lists, another number, and another list of lists.
My input looks like this:
5
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
5
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
And I want the names first_num, first_arrangement, second_num, second_arrangement such that:
first_num == 5
first_arrangement == [[1, 2, 3, 4], [5, 6, 7, 8], ...]
and so on.
To do this, it'd be useful to be able to consume a set number of items from the iterable I've got yielding the lines. Something like this would be ideal as an intermediate step:
first_num, *[4]first_arrangement, second_num, *[4]second_arrangement = lines
What's the normal/canonical/Pythonic way of solving this?
I think the canonical, pythonic way to do this would be to put the onus on the generator that you're iterating over. I'd define a generator function like so:
import itertools
def generate_arrangements(iterable, size=4):
    iterator = iter(iterable)
    while True:
        yield next(iterator)
        yield list(list(row) for row in itertools.islice(iterator, size))
Say you have your data in a list like so:
data = [
    5,
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
    [13, 14, 15, 16],
    5,
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
    [13, 14, 15, 16]
]
Then writing:
first_num, first_arr, second_num, second_arr = generate_arrangements(data)
gives you your desired output:
>>> first_num
5
>>> first_arr
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
You can also yield the number and arrangement at the same time, and have the user do some extra unpacking, which might be a more natural approach:
import itertools
def generate_arrangements(iterable):
    iterator = iter(iterable)
    while True:
        number =  next(iterator)
        arrangement = list(list(row) for row in itertools.islice(iterator, 4))
        yield number, arrangement
(first_num, first_arr), (second_num, second_arr) = generate_arrangements(data)
As @JoranBeasley writes in the comments, this form makes it easy to use tuple unpacking in a for-loop, like this:
for num,arr in generate_arrangements(data):
    print(num) 
    print(arr)
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With