20

将“更好”理解为更快、更优雅、更易读。

我有两个字符串 ( aand b) 可以为空或不为空。只有当两者都不为空时,我才想用连字符分隔它们:

a - b

a(如果 b 为空)

b(其中 a 为空)

4

10 回答 10

47
# Concatenates a and b with ' - ' or Coalesces them if one is None
'-'.join([x for x in (a,b) if x])

编辑
这里是这个算法的结果(注意 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])
''

*另请注意,Rafael 在下面的帖子中的评估仅显示 1000 次过滤方法迭代的差异只有 0.0002 秒,可以推断出如此小的差异可能是由于当时可用系统资源的不一致造成的运行脚本。我在几次迭代中运行了他的 timeit 实现,发现这两种算法在大约 50% 的时间里都会更快,而且幅度都不大。从而表明它们基本上是等价的。

于 2013-03-12T12:21:32.880 回答
36

像这样简单的东西怎么样:

# 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

编辑:这个线程中有很多有趣的解决方案。我选择这个解决方案是因为我强调可读性和快速性,至少在实现方面是这样。它不是最具可扩展性或最有趣的解决方案,但在这个范围内它是有效的,并且让我可以非常快速地处理下一个问题。

于 2013-03-12T12:21:47.630 回答
31

哇,这似乎是一个热门问题: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行为''与此代码类似。

于 2013-03-12T12:45:17.387 回答
12

这是一种选择:

("%s - %s" if (a and b) else "%s%s") % (a,b)

编辑:正如 mgilson 所指出的,这段代码会以None“更好的方式(但可读性较差)失败”是:

"%s - %s" % (a,b) if (a and b) else (a or b)
于 2013-03-12T12:19:09.677 回答
4

我只是想提供 toxotes 的解决方案,使用format.

output = "{0} - {1}".format(a, b) if (a and b) else (a or b)
于 2013-03-12T18:28:58.740 回答
3

这里有很多答案:)

两个最佳答案(一行中的性能和干净代码)是@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作为函数 infilter产生相同的结果并且具有更好的性能:

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 次迭代的毫秒数(每次迭代微秒)为单位。所以这两种方法的性能相当,而且,对于几乎任何项目,你都可以选择任何一种;如果你的项目必须有更好的性能,考虑到微秒,你可以遵循这个基准:)

于 2013-03-12T13:42:55.117 回答
1

像这样做: '-'.join(max(x,'') for x in [a,b] if x is not None)

于 2020-04-14T10:14:06.943 回答
0

试试这个:

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
于 2013-03-12T12:21:56.307 回答
0

一些pythonian,可读和优雅:

strings = string1, string2

'{0}{1}{2}'.format(
    # output first string if it's 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's not empty
    strings[1] if strings[1] else ''
    )

而且也很快;)

于 2013-03-12T16:28:27.267 回答
0

我会这样做:

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'
于 2013-03-12T16:30:38.760 回答