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.
'-'. It's pretty idiomatic to leave them off -- In fact, I've seen it written with parenthesis so rarely that the parenthesis actually made me take a second look at this.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.
output = a or b or 'default' instead of setting it beforehand?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.
filter(None,(a,b)) would also work, but bool is probably a little more explicit. For the record, this really isn't any different than the version above which uses a list-comp instead.bool I get a slight decrease in performance. Probably because passing None allows to call the truth methods more directly, while passing bool the filter has to do a normal function call.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)
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 :)
setup declaration and I've missed a ) in your code, fixed now!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
else if the preceding if will return from the function. I often wondered if it should be included for readability, but decided against it. It'd be nice if we could do return a if b else c.return a if b else creturn (a if b else c)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 ;)