Czy można podzielić ciąg co n-ty znak?
Załóżmy na przykład, że mam ciąg znaków zawierający następujące elementy:
'1234567890'
Jak mogę to wyglądać tak:
['12','34','56','78','90']
Czy można podzielić ciąg co n-ty znak?
Załóżmy na przykład, że mam ciąg znaków zawierający następujące elementy:
'1234567890'
Jak mogę to wyglądać tak:
['12','34','56','78','90']
Odpowiedzi:
>>> line = '1234567890'
>>> n = 2
>>> [line[i:i+n] for i in range(0, len(line), n)]
['12', '34', '56', '78', '90']
Aby być kompletnym, możesz to zrobić za pomocą wyrażenia regularnego:
>>> import re
>>> re.findall('..','1234567890')
['12', '34', '56', '78', '90']
W przypadku nieparzystej liczby znaków możesz to zrobić:
>>> import re
>>> re.findall('..?', '123456789')
['12', '34', '56', '78', '9']
Możesz również wykonać następujące czynności, aby uprościć wyrażenie regularne dla dłuższych fragmentów:
>>> import re
>>> re.findall('.{1,2}', '123456789')
['12', '34', '56', '78', '9']
I możesz użyć, re.finditer
jeśli ciąg jest długi, aby wygenerować porcję po porcji.
'.'*n
aby było bardziej jasne. Bez łączenia, bez zipowania, bez pętli, bez zrozumienia listy; po prostu znajdź obok siebie kolejne dwie postacie, dokładnie tak, jak myśli o tym ludzki mózg. Gdyby Monty Python nadal żył, pokochałby tę metodę!
flags=re.S
.
W tym języku jest już wbudowana funkcja.
>>> from textwrap import wrap
>>> s = '1234567890'
>>> wrap(s, 2)
['12', '34', '56', '78', '90']
Oto, co mówi dokument do zawijania:
>>> 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.
'''
wrap
może nie zwrócić tego, o co jest poproszony, jeśli ciąg zawiera spację. np. wrap('0 1 2 3 4 5', 2)
zwraca ['0', '1', '2', '3', '4', '5']
(elementy są rozebrane)
Innym popularnym sposobem grupowania elementów w grupy o długości n:
>>> s = '1234567890'
>>> map(''.join, zip(*[iter(s)]*2))
['12', '34', '56', '78', '90']
Ta metoda pochodzi prosto z dokumentacji dla zip()
.
zip(*[iter(s)]*2)
trudno jest zrozumieć, przeczytaj Jak zip(*[iter(s)]*n)
działa Python? .
>>> map(''.join, zip(*[iter('01234567')]*5))
->['01234']
zip()
z itertools.zip_longest()
:map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
Myślę, że jest to krótszy i bardziej czytelny niż wersja itertools:
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)))
Możesz użyć grouper()
przepisu z itertools
:
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)
from itertools import zip_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 zip_longest(*args, fillvalue=fillvalue)
Funkcje te są wydajne pod względem pamięci i działają z dowolnymi iteracjami.
Wypróbuj następujący kod:
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)))
yield ''.join(piece)
aby działała zgodnie z oczekiwaniami: eval.in/813878
>>> 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']
Spróbuj tego:
s='1234567890'
print([s[idx:idx+2] for idx,val in enumerate(s) if idx%2 == 0])
Wynik:
['12', '34', '56', '78', '90']
Jak zawsze dla tych, którzy kochają jedną wkładkę
n = 2
line = "this is a line split into n characters"
line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]
print(line)
otrzymuję this is a line split into n characters
jako wynik. Może być lepiej oddanie: line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]
? Napraw to i to dobra odpowiedź :).
,blah
i dlaczego jest to konieczne? Zauważyłem, że mogę zastąpić blah
dowolnym znakiem / literami alfa, ale nie cyframi, i nie mogę usunąć blah
przecinka lub. Mój redaktor sugeruje dodanie spacji po ,
: s
enumerate
zwraca dwie iterowalne, więc potrzebujesz dwóch miejsc do ich umieszczenia. Ale w tym przypadku tak naprawdę nie potrzebujesz drugiej iteracji.
blah
wolę używać podkreślenia lub podwójnego podkreślenia, patrz: stackoverflow.com/questions/5893163/…
Proste rekurencyjne rozwiązanie dla krótkiego łańcucha:
def split(s, n):
if len(s) < n:
return []
else:
return [s[:n]] + split(s[n:], n)
print(split('1234567890', 2))
Lub w takiej formie:
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)
, która bardziej szczegółowo ilustruje typowy wzór dziel i zwyciężaj w podejściu rekurencyjnym (chociaż praktycznie nie jest to konieczne)
more_itertools.sliced
zostało wspomniane wcześniej. Oto cztery dodatkowe opcje z more_itertools
biblioteki:
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)]
Każda z tych ostatnich opcji generuje następujące dane wyjściowe:
['12', '34', '56', '78', '90']
Dokumentacja dla omawianych opcji: grouper
, chunked
, windowed
,split_after
Można to osiągnąć za pomocą prostej pętli for.
a = '1234567890a'
result = []
for i in range(0, len(a), 2):
result.append(a[i : i + 2])
print(result)
Wyjście wygląda następująco: „12”, „34”, „56”, „78”, „90”, „a”]