Какой лучший способ конкатенировать строку в python?
Понять "лучше" как более быструю, элегантную и удобочитаемую.
У меня есть две строки (a
и b
), которые могут быть нулевыми или нет. И я хочу объединить их, разделенные дефисом, только если оба значения не равны нулю:
a - b
a
(если b равно null)
b
(где a равно null)
Ответы
Ответ 1
# Concatenates a and b with ' - ' or Coalesces them if one is None
'-'.join([x for x in (a,b) if x])
Edit
Вот результаты этого алгоритма (обратите внимание, что None будет работать так же, как ''):
>>> '-'.join([x for x in ('foo','bar') if x])
'foo-bar'
>>> '-'.join([x for x in ('foo','') if x])
'foo'
>>> '-'.join([x for x in ('','bar') if x])
'bar'
>>> '-'.join([x for x in ('','') if x])
''
* Также обратите внимание на то, что оценка Рафаэля в его сообщении ниже показала разницу в 0,0002 секунды над 1000 итерациями метода фильтра, можно предположить, что такая небольшая разница может быть связана с несогласованностью в доступных системных ресурсах во время запуска script. Я выполнил его timeit-реализацию на нескольких итерациях и обнаружил, что любой алгоритм будет быстрее примерно в 50% случаев, ни с большим отрывом. Таким образом, они в основном эквивалентны.
Ответ 2
Как насчет чего-то простого:
# if I always need a string even when `a` and `b` are both null,
# I would set `output` to a default beforehand.
# Or actually, as Supr points out, simply do `a or b or 'default'`
if a and b:
output = '%s - %s' % (a, b)
else:
output = a or b
Изменить: много интересных решений в этой теме. Я выбрал это решение, потому что я подчеркивал удобочитаемость и быстроту, по крайней мере, с точки зрения реализации. Это не самое масштабируемое или интересное решение, но для этой области действия оно работает и позволяет быстро перейти к следующей проблеме.
Ответ 3
Ничего себе, похоже, горячий вопрос: p Мое предложение:
' - '.join(filter(bool, (a, b)))
Что дает:
>>> ' - '.join(filter(bool, ('', '')))
''
>>> ' - '.join(filter(bool, ('1', '')))
'1'
>>> ' - '.join(filter(bool, ('1', '2')))
'1 - 2'
>>> ' - '.join(filter(bool, ('', '2')))
'2'
Очевидно, что None
ведет себя как ''
с этим кодом.
Ответ 4
Вот один из вариантов:
("%s - %s" if (a and b) else "%s%s") % (a,b)
EDIT: как указано в mgilson, этот код не смог бы с None
лучшим способом (но менее читаемым):
"%s - %s" % (a,b) if (a and b) else (a or b)
Ответ 5
Я просто хотел предложить решение для токенов, переписанное как один вкладыш, используя format
.
output = "{0} - {1}".format(a, b) if (a and b) else (a or b)
Ответ 6
Здесь много ответов:)
Два лучших ответа (производительность и чистый код в одной строке) - это ответы @icecrime и @Hoopdady
Оба варианта равны, единственная разница - производительность.
cases = [
(None, 'testB'),
('', 'testB'),
('testA', 'testB'),
('testA', ''),
('testA', None),
(None, None)
]
for case in cases: print '-'.join(filter(bool, case))
'testB'
'testB'
'testA-testB'
'testA'
'testA'
for case in cases: print '-'.join([x for x in case if x])
'testB'
'testB'
'testA-testB'
'testA'
'testA'
Итак, давайте сравним:)
import timeit
setup = '''
cases = [
(None, "testB"),
("", "testB"),
("testA","testB"),
("testA", ""),
("testA", None),
(None, None)
]
'''
print min(timeit.Timer(
"for case in cases: '-'.join([x for x in case if x])", setup=setup
).repeat(5, 1000))
0.00171494483948
print min(timeit.Timer(
"for case in cases: '-'.join(filter(bool, case))", setup=setup
).repeat(5, 1000))
0.00283288955688
Но, как сказал @mgilson, используя None
вместо bool
, поскольку функция в filter
дает тот же результат и имеет довольно высокую производительность:
print min(timeit.Timer(
"for case in cases: '-'.join(filter(None, case))", setup=setup
).repeat(5, 1000))
0.00154685974121
Итак, лучший результат - это ответ, полученный @icecrime с предложением от @mgilson:
'-'.join(filter(None, (a,b)))
Разница в производительности составляет миллисекунды на 1000 итераций (микросекунды на итерацию). Таким образом, эти два метода имеют совершенно равную производительность, и для практически любого проекта вы можете выбрать любой; Если ваш проект должен иметь лучшую производительность, учитывая микросекунды, вы можете следовать этому эталону:)
Ответ 7
Попробуйте следующее:
def myfunc(a,b):
if not b:
return a
elif not a:
return b
else:
return a+' - '+b
или
def myfunc(a,b):
if a and b:
return a+' - '+b
else:
return a or b
Ответ 8
Что-то питонское, читаемое и элегантное:
strings = string1, string2
'{0}{1}{2}'.format(
# output first string if it not empty
strings[0] if strings[0] else '',
# join with hyphen if both strings are not empty
'-' if all(strings) else '',
# output second string if it not empty
strings[1] if strings[1] else ''
)
И быстро тоже;)
Ответ 9
Я бы сделал это следующим образом:
def show_together(item1=None, item2=None, seperator='-'):
return '%s%s%s' % (item1,seperator,item2) if item1 and item2 else item1 or item2
>>> show_together(1,1)
'1-1'
>>> show_together(1)
1
>>> show_together()
>>> show_together(4,4,'$')
'4$4'