I've been going through Automatetheboringstuff and came across a challenge called Comma Code (end of chapter 4). You have to write a function that takes a list and print out a string, joining the elements with a comma and adding "and" before the last element.
Keeping in mind that I am fairly new to python, or programing for that matter, it was still a manageable task, but the output had a comma before the inserted "and". So I revised the code to clean that up. This is my code:
def comma_separator(someList):
"""The function comma_separator takes a list and joins it
into a string with (", ") and adds " and " before the last value."""
if type(someList) is list and bool(someList) is True:
return ", ".join(someList[:-1]) + " and " + someList[-1]
else:
print("Pass a non-empty list as the argument.")
Is there a better way to do it? Is there a module that can do this?
You'll have to account for the case where you have just the one element:
def comma_separator(sequence):
if not sequence:
return ''
if len(sequence) == 1:
return sequence[0]
return '{} and {}'.format(', '.join(sequence[:-1]), sequence[-1])
Note that bool(sequence) is True
is a very elaborate way of testing for a non-empty list; simply using if sequence:
is enough as the if
statement looks for boolean truth already.
Arguably, calling the function with anything other than a sequence (something that can be indexed and has a length) should just result in an exception. You generally do not test for types in functions like these. If you did have to test for a type, use isinstance(sequence, list)
to at least allow for subclasses.
I'd also make it an error to pass in an empty list. You could turn that exception into a ValueError
:
def comma_separator(sequence):
if len(sequence) > 1:
return '{} and {}'.format(', '.join(sequence[:-1]), sequence[-1])
try:
return sequence[0]
except IndexError:
raise ValueError('Must pass in at least one element')
Demo of the latter:
>>> def comma_separator(sequence):
... if len(sequence) > 1:
... return '{} and {}'.format(', '.join(sequence[:-1]), sequence[-1])
... try:
... return sequence[0]
... except IndexError:
... raise ValueError('Must pass in at least one element')
...
>>> comma_separator(['foo', 'bar', 'baz'])
'foo, bar and baz'
>>> comma_separator(['foo', 'bar'])
'foo and bar'
>>> comma_separator(['foo'])
'foo'
>>> comma_separator([])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in comma_separator
ValueError: Must pass in at least one element
As an alternative to Martijn's readable answer, you can use two str.join()
; an inner join that joins with commas all but the last item in the given sequence, and an outer join that joins with and
the result of the inner join with the last item. It's a one-liner:
def comma_separator(seq):
return ' and '.join([', '.join(seq[:-1]), seq[-1]] if len(seq) > 2 else seq)
>>> comma_separator([])
''
>>> comma_separator(['a'])
'a'
>>> comma_separator(['a', 'b'])
'a and b'
>>> comma_separator(['a', 'b', 'c'])
'a, b and c'
>>> comma_separator(['a', 'b', 'c', 'd'])
'a, b, c and d'
This does not treat an empty sequence as an error but instead returns an empty string.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With