1
\$\begingroup\$

Comma Code

Say you have a list value like this:

spam = ['apples', 'bananas', 'tofu', 'cats']

Write a function that takes a list value as an argument and returns a string with all the items separated by a comma and a space, with and inserted before the last item. For example, passing the previous spam list to the function would return 'apples, bananas, tofu, and cats'. But your function should be able to work with any list value passed to it.

# Function for getting user input.
def get_input():
    user_input = input('Enter some random stuff: ')
    return user_input

# Function for appending the input to the list
def logic_code(input, big_list):
    big_list.append(input)
    return big_list
    
# Function for printing the output
def print_output(big_list):
    while True:
        input = get_input()
        if input == 'Done': # If user input == 'Done', break loop.
            break
        logic_output = logic_code(input, big_list) # Output of logic_code
    output = print(logic_output)
    return output

def main() -> None:
    big_list = []
    print('Type Done to stop.')
    output = print_output(big_list)
    


if __name__ == '__main__': # Program starts here, then main() get's called.
    main()

This was a 'simple' exercise; I had to think a bit more with everything being a function, bit it looks a lot neater.

Everything is in functions; could I have handle the user input differently?

Should int and floats be in a separate list?

\$\endgroup\$
4
  • 2
    \$\begingroup\$ This is very much not what the specification asked for. It doesn't require user input, and it does require the word and \$\endgroup\$
    – Reinderien
    Jun 11, 2023 at 12:28
  • \$\begingroup\$ @Reinderien Dam my bad looks like i went to quickly, but i thought this meant user input = But your function should be able to work with any list value passed to it. \$\endgroup\$ Jun 11, 2023 at 15:02
  • \$\begingroup\$ Are you sure about the comma before "and"? Does not look quite right to me... \$\endgroup\$
    – slepic
    Jun 12, 2023 at 4:28
  • 1
    \$\begingroup\$ @slepic, that's known as an Oxford comma (also as Serial, or Harvard, comma), and the example in the spec shows it clearly is required here. \$\endgroup\$ Jun 12, 2023 at 5:43

3 Answers 3

2
\$\begingroup\$

The problem statement asks for

a function that takes a list value as an argument and returns a string

That's not what we have here. This requirement means our function should have the following form:

def join_strings(items: list[str]) -> str:
    '''
    Combine the members of "items" into a single string,
    with commas between each item, and 'and' before the last.
    '''

I've used type annotations to be completely clear about the inputs and outputs. Even if you've not seen these before, I think you should be able to see how they describe this function.

We can test it manually like this:

if __name__ == '__main__':
    print(join_strings(ham', 'eggs', 'sausage', 'spam']))

Or we can use doctest to embed some automated testing as examples in our documentation string:

def join_strings(items: list[str]) -> str:
    '''
    Combine the members of "items" into a single string,
    with commas between each item, and 'and' before the last.

    For example:

    >>> join_strings(['Dave Dee', 'Dozy', 'Beaky', 'Mick', 'Tich'])
    'Dave Dee, Dozy, Beaky, Mick, and Tich'

    >>> join_strings(['ham', 'eggs', 'sausage', 'spam'])
    'ham, eggs, sausage, and spam'

    >>> join_strings(['fish', 'chips'])
    'fish, and chips'

    >>> join_strings(['soup'])
    'soup'
    '''

We exercise these tests by adding a couple of lines (don't worry if this looks like magic - for now, just consider it the standard incantation for self-tested code):

if __name__ == '__main__':
    import doctest
    doctest.testmod()

With that framework in place, I encourage you to re-write the logic so that matches the requirements.

\$\endgroup\$
3
  • \$\begingroup\$ I posted a new version as a new question or should i have just edited this one? Also could you explain this: def join_strings(items: list[str]) -> str: for what reason do you use items: list[str], is that part of the type annotation? Thank you for the reply's it is very helpful to get feedback from outside! \$\endgroup\$ Jun 12, 2023 at 7:31
  • 1
    \$\begingroup\$ Yes, that says that the items argument is a list of strings, and the result of the function is a single string. \$\endgroup\$ Jun 12, 2023 at 7:46
  • 1
    \$\begingroup\$ And yes, a new question is the right thing to do - don't change code in a question when it has been answered. Full explanation in I improved my code based on the reviews. What next? \$\endgroup\$ Jun 12, 2023 at 7:48
2
\$\begingroup\$

Not all edge cases are handled. Separating the main logic and user input was a good idea, but you should contain all aspects of the said function. For example, everything related to the input is inside get_input(). It should just return all the words in a list. Everything related to the logic should go to the logic_function. Which is you are adding words with a comma and a space and adding a and before the last word. Here is an example:

# Function for getting user input.
def get_input():
    print("Type Done to stop.")
    words = []
    while True:
        user_input = input("Enter words: ")
        if user_input.lower() == "done":
            return words
        words.append(user_input)

# The logic
def concatenate_words(words: list):
    if len(words) > 1:
        words[-1] = "and " + words[-1]
    sentence = ", ".join(words)
    return sentence

def print_output():
    words = get_input()
    sentence = concatenate_words(words)
    print(sentence)

def main():
    print_output()

if __name__ == '__main__':
    main()

Again, not all edge cases are handled, and there are other ways to do it, but keep things simple, readable, and testable is the way to go.

\$\endgroup\$
0
-1
\$\begingroup\$

You don't need that much code to turn the list into a sentence:

def sentencefromlist(listinput):
 l = list(listinput) # Assigns the list form of the argument to the variable 'l'.
 l[-1] = 'and ' + l[-1] # Prepends the string 'and ' to the last item in the list.
 return ', '.join(l) # Returns the whole list concatenated together as a string, with each item split by ', '.

Now for the function that collects user input:

def getinput():
 l=[] # Initialise an empty list.
 while True: # Repeats forever, or until the programme encounters a break statement.
  i=input("Please enter the next item, or 'Done' if you have entered all the items: ") # Gets user input for the next item.
  if i == "Done": # Checks if the input was 'Done'.
   break # Breaks out of the loop if the input was 'Done'.
  l.append(i) # Appends the input. Will not be reached if the break statement was activated.
 return l # Returns the list with the user input.

With this, main() is simply a function chain, so we can pack it into a lambda easily:

main=lambda:print(sentencefromlist(getinput())) # Defines the variable 'main' as a lambda function the prints the return value of the 'sentencefromlist' function when given the argument 'getinput()'.
if __name__ == '__main__': # Checks if this is the main script
 main() # Runs the lambda function in the variable 'main' if this is the main script.

The full code:

def sentencefromlist(listinput):
 l = list(listinput) # Assigns the list form of the argument to the variable 'l'.
 l[-1] = 'and ' + l[-1] # Prepends the string 'and ' to the last item in the list.
 return ', '.join(l) # Returns the whole list concatenated together as a string, with each item split by ', '.

def getinput():
 l=[] # Initialise an empty list.
 while True: # Repeats forever, or until the programme encounters a break statement.
  i=input("Please enter the next item, or 'Done' if you have entered all the items: ") # Gets user input for the next item.
  if i == "Done": # Checks if the input was 'Done'.
   break # Breaks out of the loop if the input was 'Done'.
  l.append(i) # Appends the input. Will not be reached if the break statement was activated.
 return l # Returns the list with the user input.

main=lambda:print(sentencefromlist(getinput())) # Defines the variable 'main' as a lambda function the prints the return value of the 'sentencefromlist' function when given the argument 'getinput()'.
if __name__ == '__main__': # Checks if this is the main script
 main() # Runs the lambda function in the variable 'main' if this is the main script.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.