Understand "better" as a quicker, elegant and readable.
I have two strings (a
and b
) that could be null or not. And I want concatenate them separated by a hyphen only if both are not null:
a - b
a
(if b is null)
b
(where a is null)
Understand "better" as a quicker, elegant and readable.
I have two strings (a
and b
) that could be null or not. And I want concatenate them separated by a hyphen only if both are not null:
a - b
a
(if b is null)
b
(where a is null)
# Concatenates a and b with ' - ' or Coalesces them if one is None
'-'.join([x for x in (a,b) if x])
Edit
Here are the results of this algorithm (Note that None will work the same as ''):
>>> '-'.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])
''
*Also note that Rafael's assessment, in his post below, only showed a difference of .0002 secs over a 1000 iterations of the filter method, it can be reasoned that such a small difference can be due to inconsistencies in available system resources at the time of running the script. I ran his timeit implementation over several iteration and found that either algorithm will be faster about 50% of the time, neither by a wide margin. Thus showing they are basically equivalent.
How about something simple like:
# 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
Edit: Lots of interesting solutions in this thread. I chose this solution because I was emphasizing readability and quickness, at least in terms of implementation. It's not the most scalable or interesting solution, but for this scope it works, and lets me move on to the next problem very quickly.
Wow, seems like a hot question :p My proposal:
' - '.join(filter(bool, (a, b)))
Which gives:
>>> ' - '.join(filter(bool, ('', '')))
''
>>> ' - '.join(filter(bool, ('1', '')))
'1'
>>> ' - '.join(filter(bool, ('1', '2')))
'1 - 2'
>>> ' - '.join(filter(bool, ('', '2')))
'2'
Obviously, None
behaves like ''
with this code.
Here is one option:
("%s - %s" if (a and b) else "%s%s") % (a,b)
EDIT: As pointed by mgilson, this code would fail on with None
's a better way (but less readable one) would be:
"%s - %s" % (a,b) if (a and b) else (a or b)
I just wanted to offer toxotes' solution rewritten as a one liner using format
.
output = "{0} - {1}".format(a, b) if (a and b) else (a or b)
There's a lot of answers here :)
The two best answers (performance and clean code in one line) are the answers of @icecrime and @Hoopdady
Both asnwers results equally, the only difference is performance.
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'
So let's do a benchmark :)
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
But, as @mgilson said, using None
instead of bool
as the function in filter
produces the same result and have a quite better performance:
print min(timeit.Timer(
"for case in cases: '-'.join(filter(None, case))", setup=setup
).repeat(5, 1000))
0.00154685974121
So, the best result is the answer gave by @icecrime with the suggestion from @mgilson:
'-'.join(filter(None, (a,b)))
The performance difference is in milliseconds per 1000 iterations (microseconds per iteration). So these two methods have a quite equals performance, and, for almost any project you could choose any one; In case your project must have a better performance, considering microseconds, you could follow this benchmark :)
Try this:
def myfunc(a,b):
if not b:
return a
elif not a:
return b
else:
return a+' - '+b
Or
def myfunc(a,b):
if a and b:
return a+' - '+b
else:
return a or b
Something pythonian, readable and elegant:
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 ''
)
And fast too ;)
I would do it like this:
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'