Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If element is in list, remove it and return new list

If an element e is in a list L, we are told to remove it and return the new list without the element.

With my current code, I get an error saying can only concatenate list (not "str") to list at the line M = [L[1]] + removeAll(e, L[2:]). Does anyone know how to fix this?

We are not allowed to use for or while statements. Thanks!

def removeAll(e, L):
    if e in L:
        if e == L[0]:
            M = [L[1]] + removeAll(e, L[2:])
        else:
            M = [L[0]] + removeAll(e, L[1:])
        return M
    return "{} is not in the list".format(e)

print (removeAll(42, [ 55, 77, 42, 11, 42, 88 ]))
like image 317
jape Avatar asked Nov 22 '25 08:11

jape


2 Answers

Your recursive function returns a string when the element is not in the (remaining) list:

if e in L:
    # ...
return "{} is not in the list".format(e)

Because you are calling this function with a shorter and shorter list, that condition is always going to be true at some point.

You then try to concatenate that string to a list, in two places:

M = [L[1]] + removeAll(e, L[2:])
# ...
M = [L[0]] + removeAll(e, L[1:])

Don't return a string, return the list unmodified, so that it can be concatenated to that other element:

def removeAll(e, L):
    if e in L:
        if e == L[0]:
            M = [L[1]] + removeAll(e, L[2:])
        else:
            M = [L[0]] + removeAll(e, L[1:])
        return M
    return L  # no need to modify, the element is not present

You don't need to test if the element is elsewhere in the list. Only test the first element and not include it if it is a match. You'll also need to account for the possibility that L is empty:

def removeAll(e, L):
    if not L:
        return []
    head = [] if L[0] == e else L[:1]
    return head + removeAll(e, L[1:])

I used a slice again to create a list with one element.

If you must test if the element was not in the list, do so outside of the function:

original = [55, 77, 42, 11, 42, 88]
changed = removeAll(42, original)
if len(original) == len(changed):
    return "42 is not in the list"

Of course, if recursion is not a course requirement for you, you'd be much better of using a list comprehension to filter the values:

def removeAll(e, L):
    return [elem for elem in L if elem != e]

This returns a new list, with any elements equal to e filtered out.

If you are allowed to alter the list in-place, use list.remove() (and catch the ValueError:

def removeAll(e, L):
    try:
        L.remove(e)
    except ValueError:
        pass
    return L

This does not create a copy; any other references to the original list will see the same change.

like image 131
Martijn Pieters Avatar answered Nov 24 '25 22:11

Martijn Pieters


Your solution almost works. You need your simple case (e is not in L) to return the unmodified list. Don't return a string. You can optionally issue a print statement if the item is not found.

def removeAll(e, L):
    if e in L:
        if e == L[0]:
            M = [L[1]] + removeAll(e, L[2:])
        else:
            M = [L[0]] + removeAll(e, L[1:])
        return M
    else:            
        #print "{} is not in the list".format(e) # optional
        return L

This would be your code with the minimum amount of fixes to make it run properly.

The short, pythonic version that fits your requirements looks like this:

def removeAll(e, L):
    return filter(lambda x: x!=e, L)

Alternatively, the equivalent code with a list comprehension:

def removeAll(e, L):
    return [x for x in L if x!=e]

I don't know if this still fits your requirements because there's a for in there (while technically, a list comprehension is not a for loop).

like image 29
timgeb Avatar answered Nov 24 '25 20:11

timgeb



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!