Merge elements from a list with the last different tab

Asked

Viewed 1,495 times

1

An exercise in a book I’m studying has the following question:

Suppose you have a list value like:

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

Create a function that accepts a list value as argument and return a string with all items separated by a comma and a space, with "and" inserted before the last item.

For example, if we pass the list spam prior to function,apples, bananas, tofu and cats will be returned. However your function should be able to work with any list value it receives.

I thought of the following resolution:

spam = ['apples','bananas','tofu','cats']
def string(lista):
    cont = 0
    for i in lista:
        if cont < (len(lista))-2:
            print(i +',',end=' ')
            cont +=1
        elif cont == (len(lista))-2:
            print(i +' and',end=' ')
            cont +=1
        else:
            print(i)
            cont+=1

At first it solves my problem, but there would be some way to write this code in a cleaner way?

  • Hello Renan... consider leaving the title with a macro bro reading. That is, try to be more specific in your questions, this is to avoid Ban on platform.

3 answers

3

You can do it by omitting the cycle:

def join_list(lista):
     str = ', '.join(lista[:-1]) # gerar uma string com os items separados por virgula, com excecao do ultimo
     return '{} and {}'.format(str, lista[-1]) # adicionar o ultimo com 'and' e retornar

spam = ['apples','bananas','tofu','cats']
print(join_list(spam)) # apples, bananas, tofu and cats

DEMONSTRATION

3


Just complementing the other answers, here are some other options.

First a solution similar to answer from Miguel, but checking the cases where the list is empty or only contains one element (after all, the exercise says that "the function should be able to work with any list value", so we should consider these cases as well):

def juntar(lista):
    if not lista:
        return ''
    if len(lista) == 1:
        return lista[0]

    s = ', '.join(lista[:-1])
    return f'{s} and {lista[-1]}'

print(juntar(['apples', 'bananas', 'tofu', 'cats'])) # apples, bananas, tofu and cats
print(juntar(['apples', 'bananas'])) # apples and bananas
print(juntar(['apples'])) # apples
print(juntar([])) # não imprime nada (somente uma linha em branco)

First I use if not lista to check if the list is empty (this works because an empty list is considered a false value). I understand that if the list is empty, the corresponding string must be "nothing" (i.e., the empty string: ''), since there’s nothing to concatenate.

Then I see the case where the list only has one element, because in this case there should be no comma and nor the and (for example, if the list is ['apples'], then the resulting string should be only apples). In this case, just return the first - and only - element from the list.

If the list has more than one element, then I use the algorithm already proposed: use join to add from the first to the penultimate element, separated by a comma plus space (lista[:-1] uses the syntax of Slice to create another list, containing from the first to the penultimate element).

Then I use a f-string to join this string with the text "and" plus the last element of the list (the f-strings are available from Python 3.6 but if you are using an earlier version, you can use format as already suggested in Miguel’s response).


Another option is to use join to join all elements separated by a comma, and then you replace the last comma with "and":

def juntar(lista):
    s = ', '.join(lista)
    i = s.rfind(', ')
    if i < 0:
        return s
    return f'{s[:i]} and {s[i + 2:]}'

print(juntar(['apples', 'bananas', 'tofu', 'cats'])) # apples, bananas, tofu and cats
print(juntar(['apples', 'bananas'])) # apples and bananas
print(juntar(['apples'])) # apples
print(juntar([])) # não imprime nada (somente uma linha em branco)

First I make a join, and the result will be a string containing all elements separated by comma and space. Then I use rfind to obtain the index of the last occurrence of ', '.

If no comma + space is found, rfind returns -1, and in this case, it means that the list had an element or was empty, so I can return the result of the join unmodified.

But if the index is found, it corresponds to the last occurrence of ', '. Then I create another string containing everything until this last occurrence (s[:i] - again using the syntax of Slice to get a piece of the string), along with "and" and the entire string after the last occurrence of the comma (s[i + 2:] - somo 2 so that you don’t pick up the comma or the space).

The only problem with this solution is when the last element contains a comma followed by space. For example, if the list is ['apples', 'bananas, cats'], the result will be apples, bananas and cats - but it’s wrong, because the last comma is part of the string 'bananas, cats' and should not be replaced. Using the first code, you get the correct result (apples and bananas, cats - After all, the comma between "bananas" and "Cats" is part of the string and should not be replaced).

  • 1

    Well played, I forgot if the list is empty or with only one element

1

I am reading the same book and starting in Python, I believe that other users will arise with the same doubt. In view of the little knowledge acquired so far, my program was like this:

spam = ['apples','bananas','tofu','cats'] # a lista apresentada no livro
def separar(item):
        frase = '' #criei uma string em branco para ir acrescentando os valores
        for i in range(int(len(item) -2)): #defini o limite da inserção das palávras na frase
            frase = frase + item[i] #somei a frase em branco item por item 
            frase = frase + ', ' #acresentei a virgula a partir do primeiro item     
            print(frase + item[-2] + ' and ' + item[-1]) # acrescentei os dois ultimos itens separadamente pois não entraram na contágem anterior.
separar(spam) #acrescentei a lista spam na função separar.

I broke my head a lot in this exercise, but it was worth learning. I hope that the answer clarifies more people.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.