Вы не можете изменять основные типы в python. Однако вы можете использовать трубу для написания более понятного для человека кода:
from pipe import *
@Pipe
def should_equal(obj, val):
if obj==val: return True
return False
class dummy: pass
item=dummy()
item.value=19.99
print item.value | should_equal(19.99)
Для меня самый pythonic * путь следующий: в значительной степени делает то же самое , но использует оператор +
для конкатенации отдельных символов в каждой строке:
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
в убедитесь, что обе строки полностью исчерпаны.
* Чтобы взять цитату из , Zen of Python : число читаемости. Pythonic = читаемость для меня; i + j
просто визуально анализируется легче, по крайней мере для моих глаз.
Потенциально быстрее и короче, чем текущее ведущее решение:
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))
Многие из этих предложений предполагают, что строки имеют одинаковую длину. Возможно, это охватывает все разумные варианты использования, но по крайней мере для меня кажется, что вы, возможно, захотите также разместить строки различной длины. Или я единственный, кто думает, что меш должен работать примерно так:
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:]])
Ответ Джима велик, но вот мой любимый вариант, если вы не возражаете против нескольких импортов:
from functools import reduce
from operator import add
reduce(add, map(add, u, l))
Другой способ:
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
Python 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
Вы можете использовать iteration_utilities.roundrobin
1
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
.
Мне нравится использовать два for
s, имена переменных могут давать подсказку / напоминание о том, что происходит:
"".join(char for pair in zip(u,l) for char in pair)
Если вам нужен самый быстрый способ, вы можете комбинировать 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
Нет такой вещи, как генератор с соединением, проходящий один, всегда будет быть медленнее, поскольку python будет сначала создавать список, используя контент, потому что он выполняет два прохода над данными, один для определения необходимого размера и один для фактического выполнения соединения, который невозможен с помощью генератора:
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'
Для 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'
Какая карта состоит в том, что каждый элемент из первого итерабельного u
и первых элементов второго итерабельного l
берет каждый элемент и применяет функцию, представленную в качестве первого аргумента add
. Затем соединение просто присоединяется к ним.
Чувствует себя немного не-pythonic, чтобы не учитывать ответ на двойной список, чтобы обрабатывать 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
С join()
и zip()
.
>>> ''.join(''.join(item) for item in zip(u,l))
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
Я хотел бы использовать zip (), чтобы получить читаемый и простой способ:
result = ''
for cha, chb in zip(u, l):
result += '%s%s' % (cha, chb)
print result
# 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
На Python 2, far , более быстрый способ сделать что-либо, при ~ 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, если вы выполняете это на массивных строках и нуждаетесь в каждом цикле, по какой-то причине, и должны использовать строки 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, это всего лишь 3 раза скорость сортировки списков для длинных строк и коэффициент от 4 до 5 медленнее для небольших строк.
В любом случае я предпочитаю решения join
но поскольку тайминги были упомянуты в другом месте, я думал, что могу присоединиться.
Просто добавьте еще один, более базовый подход:
st = ""
for char in u:
st = "{0}{1}{2}".format( st, char, l[ u.index( char ) ] )