14 ответов:
для меня самый питонический * способ-это следующий, который в значительной степени делает то же самое но использует
+оператор для объединения отдельных символов в каждой строке: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в Python 2) сitertoolsмодуль, чтобы убедиться, что обе строки полностью исчерпаны.
*взять цитату из Дзен питона: читабельность счету.
Для Python = читабельности для меняi + jпросто визуально легче воспринимать, по крайней мере для моих глаз.
Более Быстрая Альтернатива
иначе:
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 loopPython 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'
на Python 2, by далеко более быстрый способ сделать что-то, при ~3x скорости нарезки списка для небольших строк и ~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")но к тому времени вы уже потеряли выигрыш по сравнению с нарезкой списка для небольших строк (это все еще 20x скорость для длинных строк), и это даже не работает для символов, отличных от ASCII.
FWIW, если вы are делать это на массивных струнах и нужно каждый цикл,и по какой-то причине приходится использовать строки Python... вот как это сделать:
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, это всего лишь 3x скорость нарезки списка для длинных строк и коэффициент от 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, передача одного всегда будет медленнее, так как python сначала построит список, используя контент, потому что он делает два прохода по данным, один чтобы выяснить размер, необходимый и один на самом деле сделать соединение, которое было бы невозможно с помощью генератора:
/* 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'для python 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
вы также можете сделать это с помощью
mapиoperator.add:from operator import add u = 'AAAAA' l = 'aaaaa' s = "".join(map(add, u, l))выход:
'AaAaAaAaAa'что карта делает это принимает каждый элемент из первого iterable
uи первые элементы из второго iterablelи применяет функцию, предоставленную в качестве первого аргументаadd. Тогда присоединяйтесь просто присоединяется к ним.
ответ Джима отличный, но вот мой любимый вариант, если вы не возражаете против нескольких импорта:
from functools import reduce from operator import add reduce(add, map(add, u, l))
многие из этих предложений предполагают строки имеют одинаковую длину. Может быть, это охватывает все разумные случаи использования, но по крайней мере мне кажется, что вы можете захотеть разместить строки разной длины тоже. Или я единственный, кто думает, что сетка должна работать немного так:
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:]])
мне нравится использовать два
fors, имена переменных могут дать подсказку / напоминание о том, что происходит:"".join(char for pair in zip(u,l) for char in pair)
просто чтобы добавить еще один, более простой подход:
st = "" for char in u: st = "{0}{1}{2}".format( st, char, l[ u.index( char ) ] )
потенциально быстрее и короче, чем текущее решение:
from itertools import chain u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' l = 'abcdefghijklmnopqrstuvwxyz' res = "".join(chain(*zip(u, l)))стратегия speed-wise заключается в том, чтобы сделать как можно больше на уровне 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))
чувствует себя немного непитоническим, чтобы не рассматривать ответ на двойной список-понимание здесь, чтобы обрабатывать n строк с усилием O (1):
"".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'как и многие ответы, самый быстрый? Наверное, нет, но простой и гибкий. Кроме того, без слишком большой добавленной сложности это немного быстрее, чем принятый ответ (в общем, добавление строки немного медленно в Python):
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
вы могли бы использовать
iteration_utilities.roundrobin1u = '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.
Я бы использовал zip (), чтобы получить читаемый и простой способ:
result = '' for cha, chb in zip(u, l): result += '%s%s' % (cha, chb) print result # 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
Comments