How to build a list of growing initials of a string with itertools?
Question:
I have a Python string:"d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4"
I want to split it into:
["d4", "d4 d5", "d4 d5 c4", ... , "d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4"]
I’m not sure how to run itertools
on it.
Answers:
itertools.accumulate
used in a plain manner is almost what you want:
>>> from itertools import accumulate
>>> s = "d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4"
>>> list(accumulate(s.split()))
['d4',
'd4d5',
'd4d5c4',
'd4d5c4e6',
'd4d5c4e6Nc3',
'd4d5c4e6Nc3Be7',
'd4d5c4e6Nc3Be7Nf3',
'd4d5c4e6Nc3Be7Nf3Nf6',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6Bf4',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6Bf40-0',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6Bf40-0e3',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6Bf40-0e3Nbd7',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6Bf40-0e3Nbd7g4',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6Bf40-0e3Nbd7g4dxc4']
If you want the spaces in there, you’ll need a custom accumulator function to add the spaces, e.g.:
>>> list(accumulate(s.split(), '{} {}'.format))
['d4',
'd4 d5',
'd4 d5 c4',
'd4 d5 c4 e6',
'd4 d5 c4 e6 Nc3',
'd4 d5 c4 e6 Nc3 Be7',
'd4 d5 c4 e6 Nc3 Be7 Nf3',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4']
This isn’t really an itertools
problem. In Haskell, the function is called inits
, but Python doesn’t have an equivalent built-in. We can write it ourselves.
def inits(xs):
yield ()
acc = []
for x in xs:
acc.append(x)
yield tuple(acc)
Note that we return newly-constructed tuples so as not to share any data between iterations. We also yield the empty tuple first, since it’s a valid prefix of a list. If you don’t want that in your output, you can filter out the first element.
Now it’s just a bit of fixing up the data with join
and split
.
my_string = "d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4"
my_moves = my_string.split(" ")
my_prefixes = map(" ".join, inits(my_moves))
print(list(my_prefixes))
You don’t need itertools at all.
Try:
s="d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4"
li=s.split()
>>> [' '.join(li[0:i]) for i in range(1,len(li)+1)]
['d4', 'd4 d5', 'd4 d5 c4', 'd4 d5 c4 e6', 'd4 d5 c4 e6 Nc3', 'd4 d5 c4 e6 Nc3 Be7', 'd4 d5 c4 e6 Nc3 Be7 Nf3', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4']
Another with itertools.accumulate
:
list(map(' '.join, accumulate(zip(s.split()))))
Here one using list comprehension, regular expressions (from re import re.finditer as r
) and slicing (s
is the string to process). This way all the splitting and joining again is not necessary:
[s[0:m.start()] for m in r(" ",s)]+[s]
With regex
:
import regex
s = "d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4"
regex.findall(r"(?<=(?: |^)(.*)(?: |$))", s)
['d4',
'd4 d5',
'd4 d5 c4',
'd4 d5 c4 e6',
'd4 d5 c4 e6 Nc3',
'd4 d5 c4 e6 Nc3 Be7',
'd4 d5 c4 e6 Nc3 Be7 Nf3',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4']
I have a Python string:"d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4"
I want to split it into:
["d4", "d4 d5", "d4 d5 c4", ... , "d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4"]
I’m not sure how to run itertools
on it.
itertools.accumulate
used in a plain manner is almost what you want:
>>> from itertools import accumulate
>>> s = "d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4"
>>> list(accumulate(s.split()))
['d4',
'd4d5',
'd4d5c4',
'd4d5c4e6',
'd4d5c4e6Nc3',
'd4d5c4e6Nc3Be7',
'd4d5c4e6Nc3Be7Nf3',
'd4d5c4e6Nc3Be7Nf3Nf6',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6Bf4',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6Bf40-0',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6Bf40-0e3',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6Bf40-0e3Nbd7',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6Bf40-0e3Nbd7g4',
'd4d5c4e6Nc3Be7Nf3Nf6Bg5h6Bf40-0e3Nbd7g4dxc4']
If you want the spaces in there, you’ll need a custom accumulator function to add the spaces, e.g.:
>>> list(accumulate(s.split(), '{} {}'.format))
['d4',
'd4 d5',
'd4 d5 c4',
'd4 d5 c4 e6',
'd4 d5 c4 e6 Nc3',
'd4 d5 c4 e6 Nc3 Be7',
'd4 d5 c4 e6 Nc3 Be7 Nf3',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4']
This isn’t really an itertools
problem. In Haskell, the function is called inits
, but Python doesn’t have an equivalent built-in. We can write it ourselves.
def inits(xs):
yield ()
acc = []
for x in xs:
acc.append(x)
yield tuple(acc)
Note that we return newly-constructed tuples so as not to share any data between iterations. We also yield the empty tuple first, since it’s a valid prefix of a list. If you don’t want that in your output, you can filter out the first element.
Now it’s just a bit of fixing up the data with join
and split
.
my_string = "d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4"
my_moves = my_string.split(" ")
my_prefixes = map(" ".join, inits(my_moves))
print(list(my_prefixes))
You don’t need itertools at all.
Try:
s="d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4"
li=s.split()
>>> [' '.join(li[0:i]) for i in range(1,len(li)+1)]
['d4', 'd4 d5', 'd4 d5 c4', 'd4 d5 c4 e6', 'd4 d5 c4 e6 Nc3', 'd4 d5 c4 e6 Nc3 Be7', 'd4 d5 c4 e6 Nc3 Be7 Nf3', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4', 'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4']
Another with itertools.accumulate
:
list(map(' '.join, accumulate(zip(s.split()))))
Here one using list comprehension, regular expressions (from re import re.finditer as r
) and slicing (s
is the string to process). This way all the splitting and joining again is not necessary:
[s[0:m.start()] for m in r(" ",s)]+[s]
With regex
:
import regex
s = "d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4"
regex.findall(r"(?<=(?: |^)(.*)(?: |$))", s)
['d4',
'd4 d5',
'd4 d5 c4',
'd4 d5 c4 e6',
'd4 d5 c4 e6 Nc3',
'd4 d5 c4 e6 Nc3 Be7',
'd4 d5 c4 e6 Nc3 Be7 Nf3',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4',
'd4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bf4 0-0 e3 Nbd7 g4 dxc4']