Reputation: 7225
For a Python list:
l = list('ABCDEFG')
How can it be turned into a list of consecutive N-tuples, with the edge cases not thrown out? Here is an example for N=3:
A
A B
A B C
B C D
C D E
D E F
E F G
F G
G
I can get close with
for first, second, third in zip(l,l[1:],l[2:]):
print(first, second, third)
But this does not include the edge cases and can not be extended easily to other N. I can patch it up with a C-looking for
loop, checking for array bound validity, but it quickly grows to be a web of nested if
statements and I'm looking for a more Pythonic solution.
Upvotes: 2
Views: 1309
Reputation: 46533
Using a simple list comprehension:
def f(seq, n):
return [seq[max(i, 0):i + n] for i in range(-n + 1, len(seq))]
This creates a sliding window of size n
over the given sequence seq
, but starts n - 1
before the beginning of the sequence. The purpose of max(i, 0)
is to disallow negative indexes, so that every slice is non-empty.
Example output:
>>> f('ABCDEFG', 2)
['A', 'AB', 'BC', 'CD', 'DE', 'EF', 'FG', 'G']
>>> f('ABCDEFG', 3)
['A', 'AB', 'ABC', 'BCD', 'CDE', 'DEF', 'EFG', 'FG', 'G']
Upvotes: 7
Reputation: 149736
You could use 3 list comprehensions to generate the edge cases and N-tuples, then just concatenate the lists:
>>> def f(l, n):
... return ([l[:i] for i in range(1, n)] +
... [l[i:i+n] for i in range(len(l) - n + 1)] +
... [l[-i:] for i in range(n-1, 0, -1)])
...
>>> f(list('ABCDEFG'), 3)
[['A'], ['A', 'B'], ['A', 'B', 'C'], ['B', 'C', 'D'], ['C', 'D', 'E'], ['D', 'E', 'F'], ['E', 'F', 'G'], ['F', 'G'], ['G']]
Upvotes: 3
Reputation: 71451
You can try this:
l = list('ABCDEFG')
n = 3
def edge_cases(l, n):
first = [l[:i+1] for i in range(n-1)]
second = [l[i:i+n-1] for i in range(len(l)-n)]
third = [l[i-n+1:] for i in range(n-1)]
yield from first+second+third
print(list(edge_cases(l, n)))
Upvotes: 1
Reputation: 78546
You can write a generator function that first yields items from the string in steps then yields from a itertools.zip_longest
object:
from itertools import zip_longest
def func(s, N=3):
lst = ['']*N
for i in range(N-1):
lst[i] = s[i]
yield tuple(lst)
yield from zip_longest(*map(lambda x: l[x:], range(N)), fillvalue='')
for i in func('ABCDEFG', 5):
print(*i)
A
A B
A B C
A B C D
A B C D E
B C D E F
C D E F G
D E F G
E F G
F G
G
Upvotes: 3