Currently working my way through this beginners book and have completed one of the practice projects \'Comma Code\' which asks the user to construct a program which:
Use str.join()
to join a sequence of strings with a delimiter. If you do so for all words except for the last, you can insert ' and '
there instead:
def list_thing(words):
if len(words) == 1:
return words[0]
return '{}, and {}'.format(', '.join(words[:-1]), words[-1])
Breaking this down:
words[-1]
takes the last element of a list. words[:-1]
slices the list to produce a new list with all words except the last one.
', '.join()
produces a new string, with all strings of the argument to str.join()
joined with ', '
. If there is just one element in the input list, that one element is returned, unjoined.
'{}, and {}'.format()
inserts the comma-joined words and the last word into a template (complete with Oxford comma).
If you pass in an empty list, the above function will raise an IndexError
exception; you could specifically test for that case in the function if you feel an empty list is a valid use-case for the function.
So the above joins all words except the last with ', '
, then adds the last word to the result with ' and '
.
Note that if there is just one word, you get that one word; there is nothing to join in that case. If there are two, you get 'word1 and word 2'
. More words produces 'word1, word2, ... and lastword'
.
Demo:
>>> def list_thing(words):
... if len(words) == 1:
... return words[0]
... return '{}, and {}'.format(', '.join(words[:-1]), words[-1])
...
>>> spam = ['apples', 'bananas', 'tofu', 'cats']
>>> list_thing(spam[:1])
'apples'
>>> list_thing(spam[:2])
'apples, and bananas'
>>> list_thing(spam[:3])
'apples, bananas, and tofu'
>>> list_thing(spam)
'apples, bananas, tofu, and cats'
I am a fairly new pythonista. In the question it was asked that the function return the list contents as a string in the format that the other solutions in this forum have 'printed' it. Following is (in my opinion) a cleaner solution to this problem.
This illustrates the comma code solution of chapter 4 [Lists] in Automate The Boring Stuff.
def comma_code(argument):
argument_in_string = ''
argument_len = len(argument)
for i in range(argument_len):
if i == (argument_len - 1):
argument_in_string = argument_in_string + 'and ' + argument[i]
return argument_in_string
argument_in_string = argument_in_string + argument[i] + ', '
spam = ['apples', 'bananas', 'tofu', 'cats']
return_value = comma_code(spam)
print(return_value)"
As it was not mentioned, here's an answer with f string, for reference:
def list_things(my_list):
print(f'{", ".join(my_list[:-1])} and {my_list[-1]}.')
An example interpolating a custom message and accepting also a string as argument:
def like(my_animals = None):
message = 'The animals I like the most are'
if my_animals == None or my_animals == '' or len(my_animals) == 0:
return 'I don\'t like any animals.'
elif len(my_animals) <= 1 or type(my_animals) == str:
return f'{message} {my_animals if type(my_animals) == str else my_animals[0]}.'
return f'{message} {", ".join(my_animals[:-1])} and {my_animals[-1]}.'
>>> like()
>>> like('')
>>> like([])
# 'I don't like any animals.'
>>> like('unicorns')
>>> like(['unicorns'])
# 'The animals I like the most are unicorns.'
>>> animals = ['unicorns', 'dogs', 'rabbits', 'dragons']
>>> like(animals)
# 'The animals I like the most are unicorns, dogs, rabbits and dragons.'
This code works no matter what data types are in the lists, boolean, int, string, float, etc.
def commaCode(spam):
count = 0
max_count = len(spam) - 1
for x in range(len(spam)):
if count < max_count:
print(str(spam[count]) + ', ', end='')
count += 1
else:
print('and ' + str(spam[max_count]))
spam1 = ['cat', 'bananas', 'tofu', 'cats']
spam2 = [23, '', True, 'cats']
spam3 = []
commaCode(spam1)
commaCode(spam2)
commaCode(spam3)
def listall(lst): # everything "returned" is class string
if not lst: # equates to if not True. Empty container is always False
return 'NONE' # empty list returns string - NONE
elif len(lst) < 2: # single value lists
return str(lst[0]) # return passed value as a string (do it as the element so
# as not to return [])
return (', '.join(str(i) for i in lst[:-1])) + ' and ' + str(lst[-1])
# joins all elements in list sent, up to last element, with (comma, space)
# AND coverts all elements to string.
# Then inserts "and". lastly adds final element of list as a string.
This isn't designed to answer the original question. It's to show how to define the function addressing all the matters requested by the book without being complex. I think that's acceptable as the original question posts the books "Comma Code" test. Important Note: Something I found confusing that might help others is. "a list value" means a value of type list or "an entire list" it doesn't mean an individual value (or slices) from "type list". Hope that's helpful
Here are the samples I used to test it:
empty = []
ugh = listall(empty)
print(type(ugh))
print(ugh)
test = ['rabbits', 'dogs', 3, 'squirrels', 'numbers', 3]
ughtest = listall(test)
print(type(ughtest))
print(ughtest)
supertest = [['ra', 'zues', 'ares'],
['rabbit'],
['Who said', 'biscuits', 3, 'or', 16.71]]
one = listall(supertest[0])
print(type(one))
print(one)
two = listall(supertest[1])
print(type(two))
print(two)
last = listall(supertest[2])
print(type(last))
print(last)
Others have given great one-liner solutions, but a good way to improve your actual implementation - and fix the fact that it does not work when elements are repeated - is to use enumerate
in the for loop to keep track of the index, rather than using index
which always finds the first occurrence of the target.
for counter, element in enumerate(list):
new_string = new_string + str(element)
if counter == (len(list)-2):
...