3

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 ]))
1
  • 1
    At some point, you will end up concatenating an str with list which is what the error message is saying just because of the last return which gives a str Commented Feb 4, 2016 at 15:38

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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).

Comments

0

Generic example:

# declare sample space;
data1a = [0, 4, 8, 9, 12]
data2a = ['one','two','three']

# output pre-processed state;
print('Initial data')
print('Data 1a: {}'.format(data1a))
print('Data 2a: {}'.format(data2a))

print('=' *40)

# copy associated lists;
data1b = data1a.copy()
data2b = data2a.copy()

# process condition
if 4 in data1b:
    data1b.remove(4)

if 'two' in data2b:
    data2b.remove('two')

# output post-processed state with respect to pre-processed state
print('Data 1a: {}'.format(data1a))
print('Data 2a: {}'.format(data2a))

print('=' *40)

print('Data 1b: {}'.format(data1b))
print('Data 2b: {}'.format(data2b))

Output:

Data 1a: [0, 4, 8, 9, 12]
Data 2a: ['one', 'two', 'three']
========================================
Data 1a: [0, 4, 8, 9, 12]
Data 2a: ['one', 'two', 'three']
========================================
Data 1b: [0, 8, 9, 12]
Data 2b: ['one', 'three']

6 Comments

This doesn't even begin to address why the OP is getting an error. Sure list.remove() is nice, but if they were asked to write a recursive function, then that's not much help.
@MartijnPieters where in his question he states that he requires an explenation, why his code doesn't work? The OP states the objective, error message received with current code and request to fix it. The above does exactly that
I interpret Does anyone know how to fix this to refer to the error message preceding it in that paragraph, so the question is Does anyone know how to fix the string concatenation with a list error?
That's cool and I agree this is one way how it could have been interpreted. However, there is no explicit requirement in the OP. Based on OP, the answer produced complies with the requirements. No for or while statements and the output produced fits the bill.
There are two other issues here: list.remove() alters the list in-place. I have the impression they need to return a copy instead. The other is that list.remove() raises a ValueError exception if the element is not present.
|

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.