как мне чередовать 2 укуса? без использования метода объединения? [Дубликат]

Вы не можете изменять основные типы в 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)
109
задан cat 14 January 2016 в 04:01
поделиться

14 ответов

Для меня самый 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 просто визуально анализируется легче, по крайней мере для моих глаз.

126
ответ дан Jim Fasarakis Hilliard 26 August 2018 в 14:29
поделиться

Потенциально быстрее и короче, чем текущее ведущее решение:

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))
3
ответ дан cdlane 26 August 2018 в 14:29
поделиться

Многие из этих предложений предполагают, что строки имеют одинаковую длину. Возможно, это охватывает все разумные варианты использования, но по крайней мере для меня кажется, что вы, возможно, захотите также разместить строки различной длины. Или я единственный, кто думает, что меш должен работать примерно так:

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:]])
7
ответ дан Christofer Ohlsson 26 August 2018 в 14:29
поделиться

Ответ Джима велик, но вот мой любимый вариант, если вы не возражаете против нескольких импортов:

from functools import reduce
from operator import add

reduce(add, map(add, u, l))
8
ответ дан knite 26 August 2018 в 14:29
поделиться

Faster Alternative

Другой способ:

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
62
ответ дан Mike Müller 26 August 2018 в 14:29
поделиться

Вы можете использовать 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 .

3
ответ дан MSeifert 26 August 2018 в 14:29
поделиться

Мне нравится использовать два for s, имена переменных могут давать подсказку / напоминание о том, что происходит:

"".join(char for pair in zip(u,l) for char in pair)
5
ответ дан Neal Fultz 26 August 2018 в 14:29
поделиться

Если вам нужен самый быстрый способ, вы можете комбинировать 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
16
ответ дан Padraic Cunningham 26 August 2018 в 14:29
поделиться

Вы также можете сделать это, используя map и operator.add :

from operator import add

u = 'AAAAA'
l = 'aaaaa'

s = "".join(map(add, u, l))

Выход:

'AaAaAaAaAa'

Какая карта состоит в том, что каждый элемент из первого итерабельного u и первых элементов второго итерабельного l берет каждый элемент и применяет функцию, представленную в качестве первого аргумента add. Затем соединение просто присоединяется к ним.

11
ответ дан root 26 August 2018 в 14:29
поделиться

Чувствует себя немного не-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
3
ответ дан scnerd 26 August 2018 в 14:29
поделиться

С join() и zip().

>>> ''.join(''.join(item) for item in zip(u,l))
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
47
ответ дан TigerhawkT3 26 August 2018 в 14:29
поделиться

Я хотел бы использовать zip (), чтобы получить читаемый и простой способ:

result = ''
for cha, chb in zip(u, l):
    result += '%s%s' % (cha, chb)

print result
# 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
2
ответ дан valeas 26 August 2018 в 14:29
поделиться

На 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 но поскольку тайминги были упомянуты в другом месте, я думал, что могу присоединиться.

17
ответ дан Veedrac 26 August 2018 в 14:29
поделиться

Просто добавьте еще один, более базовый подход:

st = ""
for char in u:
    st = "{0}{1}{2}".format( st, char, l[ u.index( char ) ] )
4
ответ дан WeRelic 26 August 2018 в 14:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: