두 개의 문자열을 함께 메시하는 가장 비단뱀적인 방법은 무엇입니까?
예를 들면 :
입력:
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
산출:
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
두 개의 문자열을 함께 메시하는 가장 비단뱀적인 방법은 무엇입니까?
예를 들면 :
입력:
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
산출:
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
답변:
나에게 가장 비단뱀적인 방법은 거의 같은 일을 하지만 +각 문자열의 개별 문자를 연결하기 위해 연산자를 사용하는 다음과 같습니다 .
res = "".join(i + j for i, j in zip(u, l))
print(res)
# 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
또한 두 번의 join()호출을 사용하는 것보다 빠릅니다 .
In [5]: l1 = 'A' * 1000000; l2 = 'a' * 1000000
In [6]: %timeit "".join("".join(item) for item in zip(l1, l2))
1 loops, best of 3: 442 ms per loop
In [7]: %timeit "".join(i + j for i, j in zip(l1, l2))
1 loops, best of 3: 360 ms per loop
더 빠른 접근 방식이 있지만 종종 코드를 난독 화합니다.
참고 : 두 입력 문자열의 길이 가 같지 않으면 더 zip짧은 문자열의 끝에서 반복을 중지 하므로 긴 문자열이 잘립니다 . 이 경우 대신 zip하나를 사용해야합니다 zip_longest( izip_longest으로부터 파이썬 2) itertools두 문자열이 완전히 소진되는 것을 보장하기 위해 모듈.
* Zen of Python 의 인용문 : 가독성이 중요합니다 .
Pythonic = 나를위한 가독성 ; i + j적어도 내 눈에는 시각적으로 더 쉽게 구문 분석됩니다.
"".join([i + j for i, j in zip(l1, l2)])그것은 확실히 빠른 것
"".join(map("".join, zip(l1, l2)))반드시 더 비단뱀적인 것은 아니지만 더 빠릅니다.
또 다른 방법:
res = [''] * len(u) * 2
res[::2] = u
res[1::2] = l
print(''.join(res))
산출:
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
더 빠른 것 같습니다.
%%timeit
res = [''] * len(u) * 2
res[::2] = u
res[1::2] = l
''.join(res)
100000 loops, best of 3: 4.75 µs per loop
지금까지 가장 빠른 솔루션보다 :
%timeit "".join(list(chain.from_iterable(zip(u, l))))
100000 loops, best of 3: 6.52 µs per loop
더 큰 문자열의 경우 :
l1 = 'A' * 1000000; l2 = 'a' * 1000000
%timeit "".join(list(chain.from_iterable(zip(l1, l2))))
1 loops, best of 3: 151 ms per loop
%%timeit
res = [''] * len(l1) * 2
res[::2] = l1
res[1::2] = l2
''.join(res)
10 loops, best of 3: 92 ms per loop
파이썬 3.5.1.
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijkl'
zip()동등)min_len = min(len(u), len(l))
res = [''] * min_len * 2
res[::2] = u[:min_len]
res[1::2] = l[:min_len]
print(''.join(res))
산출:
AaBbCcDdEeFfGgHhIiJjKkLl
itertools.zip_longest(fillvalue='')동등 함).min_len = min(len(u), len(l))
res = [''] * min_len * 2
res[::2] = u[:min_len]
res[1::2] = l[:min_len]
res += u[min_len:] + l[min_len:]
print(''.join(res))
산출:
AaBbCcDdEeFfGgHhIiJjKkLlMNOPQRSTUVWXYZ
로 join()와 zip().
>>> ''.join(''.join(item) for item in zip(u,l))
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
''.join(itertools.chain.from_iterable(zip(u, l)))
zip짧으면 목록이 잘 리며, 더 짧은 목록이 완전히 반복되면 중지됩니다.
itertools.zip_longest문제가되는 경우 사용할 수 있습니다.
Python 2에서 작업을 수행 하는 가장 빠른 방법은 작은 문자열의 경우 목록 분할 속도의 ~ 3 배, 긴 문자열의 경우 ~ 30x입니다.
res = bytearray(len(u) * 2)
res[::2] = u
res[1::2] = l
str(res)
그러나 이것은 Python 3에서 작동하지 않습니다. 다음과 같은 것을 구현할 수 있습니다.
res = bytearray(len(u) * 2)
res[::2] = u.encode("ascii")
res[1::2] = l.encode("ascii")
res.decode("ascii")
그러나 그때까지 당신은 이미 작은 문자열에 대한 목록 슬라이싱에 대한 이득을 잃어 버렸고 (긴 문자열의 경우 여전히 20 배의 속도) 이것은 비 ASCII 문자에서도 작동하지 않습니다.
FWIW, 당신이 경우에 하는 대규모 문자열에이 일을 모든 사이클을 필요로 하고 어떤 이유로 파이썬 문자열을 사용해야합니다 ... 여기 그 방법은 다음과 같습니다
res = bytearray(len(u) * 4 * 2)
u_utf32 = u.encode("utf_32_be")
res[0::8] = u_utf32[0::4]
res[1::8] = u_utf32[1::4]
res[2::8] = u_utf32[2::4]
res[3::8] = u_utf32[3::4]
l_utf32 = l.encode("utf_32_be")
res[4::8] = l_utf32[0::4]
res[5::8] = l_utf32[1::4]
res[6::8] = l_utf32[2::4]
res[7::8] = l_utf32[3::4]
res.decode("utf_32_be")
작은 유형의 일반적인 경우를 특수 케이스로 지정하는 것도 도움이됩니다. FWIW, 이것은 긴 문자열의 경우 목록 분할 속도의 3 배에 불과 하고 작은 문자열 의 경우 4 ~ 5 배 더 느립니다 .
어느 쪽이든 join솔루션을 선호 하지만 타이밍이 다른 곳에서 언급되었으므로 참여하는 것이 좋을 것이라고 생각했습니다.
가장 빠른 방법을 원한다면 itertools 를 operator.add다음 과 결합 할 수 있습니다 .
In [36]: from operator import add
In [37]: from itertools import starmap, izip
In [38]: timeit "".join([i + j for i, j in uzip(l1, l2)])
1 loops, best of 3: 142 ms per loop
In [39]: timeit "".join(starmap(add, izip(l1,l2)))
1 loops, best of 3: 117 ms per loop
In [40]: timeit "".join(["".join(item) for item in zip(l1, l2)])
1 loops, best of 3: 196 ms per loop
In [41]: "".join(starmap(add, izip(l1,l2))) == "".join([i + j for i, j in izip(l1, l2)]) == "".join(["".join(item) for item in izip(l1, l2)])
Out[42]: True
그러나 결합 izip하고 chain.from_iterable다시 더 빠릅니다
In [2]: from itertools import chain, izip
In [3]: timeit "".join(chain.from_iterable(izip(l1, l2)))
10 loops, best of 3: 98.7 ms per loop
chain(*와 사이에도 상당한 차이가 있습니다
chain.from_iterable(....
In [5]: timeit "".join(chain(*izip(l1, l2)))
1 loops, best of 3: 212 ms per loop
조인이있는 생성기와 같은 것은 없습니다. 하나를 전달하는 것은 데이터에 대해 두 번의 전달을 수행하기 때문에 먼저 콘텐츠를 사용하여 목록을 작성하기 때문에 하나를 전달하는 것이 항상 느려질 것입니다. 하나는 필요한 크기를 파악하고 하나는 실제로 수행하기 때문입니다. 생성기로는 불가능한 조인 :
join.h :
/* Here is the general case. Do a pre-pass to figure out the total
* amount of space we'll need (sz), and see whether all arguments are
* bytes-like.
*/
또한 길이가 다른 문자열이 있고 데이터를 잃지 않으려면 izip_longest 사용할 수 있습니다 .
In [22]: from itertools import izip_longest
In [23]: a,b = "hlo","elworld"
In [24]: "".join(chain.from_iterable(izip_longest(a, b,fillvalue="")))
Out[24]: 'helloworld'
파이썬 3의 경우 zip_longest
그러나 python2의 경우 veedrac의 제안이 훨씬 빠릅니다.
In [18]: %%timeit
res = bytearray(len(u) * 2)
res[::2] = u
res[1::2] = l
str(res)
....:
100 loops, best of 3: 2.68 ms per loop
list? 필요로하지 않는됩니다
"".join(list(...))나에게 6.715280318699769을주고 timeit은 "".join(starmap(...))나에게 6.46332361384313 제공
"".join(list(starmap(add, izip(l1,l2))))가 "".join(starmap(add, izip(l1,l2))). 나는 내 컴퓨터에서 파이썬 2.7.11과 파이썬 3.5.1에서 테스트를 실행한다. 심지어 www.python.org 의 가상 콘솔에서도 파이썬 3.4.3을 사용하고 모두 똑같이 말하고 몇 번 실행하고 항상 같은
map및 operator.add다음을 사용하여이 작업을 수행 할 수도 있습니다 .
from operator import add
u = 'AAAAA'
l = 'aaaaa'
s = "".join(map(add, u, l))
출력 :
'AaAaAaAaAa'
어떤 맵 않는 것은 처음부터 반복 가능한 모든 요소 걸립니다 u번째 반복 가능한로부터 첫번째 요소를 l첫 번째 인수로서 기능하고 적용 add. 그런 다음 조인은 그들을 조인합니다.
이러한 제안의 대부분은 문자열 길이가 같다고 가정합니다. 아마도 모든 합리적인 사용 사례를 다룰 수 있지만 적어도 나에게는 길이가 다른 문자열도 수용하고 싶을 것 같습니다. 아니면 메시가 다음과 같이 작동해야한다고 생각하는 유일한 사람입니까?
u = "foobar"
l = "baz"
mesh(u,l) = "fboaozbar"
이를 수행하는 한 가지 방법은 다음과 같습니다.
def mesh(a,b):
minlen = min(len(a),len(b))
return "".join(["".join(x+y for x,y in zip(a,b)),a[minlen:],b[minlen:]])
O (1) 노력으로 n 문자열을 처리하기 위해 여기에서 이중 목록 이해 답변을 고려하지 않는 것이 비단 식적이라고 느낍니다.
"".join(c for cs in itertools.zip_longest(*all_strings) for c in cs)
all_strings인터리브하려는 문자열 목록은 어디에 있습니까 ? 귀하의 경우 all_strings = [u, l]. 전체 사용 예는 다음과 같습니다.
import itertools
a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
b = 'abcdefghijklmnopqrstuvwxyz'
all_strings = [a,b]
interleaved = "".join(c for cs in itertools.zip_longest(*all_strings) for c in cs)
print(interleaved)
# 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
많은 답변처럼 빠른가요? 아마 아니지만 간단하고 유연합니다. 또한 복잡성을 너무 많이 추가하지 않으면 허용되는 답변보다 약간 빠릅니다 (일반적으로 문자열 추가는 파이썬에서 약간 느립니다).
In [7]: l1 = 'A' * 1000000; l2 = 'a' * 1000000;
In [8]: %timeit "".join(a + b for i, j in zip(l1, l2))
1 loops, best of 3: 227 ms per loop
In [9]: %timeit "".join(c for cs in zip(*(l1, l2)) for c in cs)
1 loops, best of 3: 198 ms per loop
현재 선도적 인 솔루션보다 잠재적으로 더 빠르고 짧습니다.
from itertools import chain
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
res = "".join(chain(*zip(u, l)))
속도 측면에서 전략은 가능한 한 C 수준에서 많은 일을하는 것입니다. 고르지 않은 문자열에 대해 동일한 zip_longest () 수정 사항이 있으며 chain ()과 동일한 모듈에서 나올 것이므로 거기에 너무 많은 포인트를 줄 수 없습니다!
그 과정에서 내가 생각 해낸 다른 솔루션 :
res = "".join(u[x] + l[x] for x in range(len(u)))
res = "".join(k + l[i] for i, k in enumerate(u))
1을 사용할 수 있습니다.iteration_utilities.roundrobin
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
from iteration_utilities import roundrobin
''.join(roundrobin(u, l))
# returns 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
또는 ManyIterables동일한 패키지 의 클래스 :
from iteration_utilities import ManyIterables
ManyIterables(u, l).roundrobin().as_string()
# returns 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
1 이것은 내가 작성한 타사 라이브러리에서 가져온 것입니다 iteration_utilities..