caleb farley
caleb farley

Reputation: 35

Writing filter() function but getting typeError

my code consists of me recreating the function 'filter()' and using it with a function to filter words longer than 5 characters. It worked with the actual function filter when I tried it btw...I'm using python 3+

def filter1(fn, a):
    i = 0
    while i != len(a):
        u = i - 1
        a[i] = fn(a[i], a[u])
        i += 1
    return a


def filter_long_words(l):
    if len[l] > 5:
        return [l]

listered = ['blue', 'hdfdhsf', 'dsfjbdsf', 'jole']
print(list(filter1(filter_long_words, listered)))

getting error

TypeError: filter_long_words() takes 1 positional argument but 2 were given

Upvotes: 0

Views: 73

Answers (3)

Jan Spurny
Jan Spurny

Reputation: 5537

Your're calling fn with 2 parameters in filter1(fn, a), and since you've passed filter_long_words() to filter1 as fn, that triggers the error.

But there's more weird stuff:

I don't understand the magick of filter1 or what you were trying to accomplish, but it seems to me that you don't have a clear idea what to do. But if you want to mimic (somehow) how filter works, you have to return a list which contains only items for which the fn function returns true. When you know this, you can rewrite it - here are a few suggestions for rewrite

# explicit, inefficient and long, but straightforward version:
def filter1(fn, a):
    new_list = []
    for item in a:
        if fn(item):
            new_list.append(item):
    return new_list

# shorter version using list comprehensions:
def filter1(fn, a):
    return [item for item in a if fn(item)]

The filter_long_words function is wrong too - it should return True or False. The only reason why it could work is because any non-empty list is treated as True by python and default return value of a function is None, which translates to False. But it's confusing and syntactically wrong to use len[l] - the proper usage is len(l). There are a few suggestions for rewrite, which all returns explicit boolean values:

# unnecessary long, but self-explanatory:
def filter_long_words(l):
    if len(l) > 5:
        return True
    else
        return False

# short variant
def filter_long_words(l):
    return len(l) > 5

Upvotes: 1

André Laszlo
André Laszlo

Reputation: 15537

You are passing two parameters to fn (which refers to filter_long_words) here:

a[i] = fn(a[i], a[u])

But filter_long_words only accepts one parameter.

Notes:

  • You can loop through lists using for item in my_list, or if you want index as well for index, item in enumerate(my_list).
  • I think you might get an IndexError since u will be -1 in the first round of your loop.
  • The filter function can also be expressed as a list comprehension: (item for item in listered if filter_long_words(item))

My version of filter would look like this, if I have to use a for loop:

def my_filter(fn, sequence):
    if fn is None:
        fn = lambda x: x
    for item in sequence:
        if fn(item):
            yield item

Since you have stated that you are using Python 3, this returns a generator instead of a list. If you want it to return a list:

def my_filter(fn, sequence):
    if fn is None:
        fn = lambda x: x
    acc = []
    for item in sequence:
        if fn(item):
            acc.append(item)
    return acc

If you don't need to use a for loop:

def my_filter(fn, sequence):
    if fn is None:
        fn = lambda x: x
    return (item for item in sequence if fn(item))

Upvotes: 1

manish
manish

Reputation: 974

You are calling "filter_long_words" with 2 parameter => fn(a[i], a[u]) also there is an error

def filter_long_words(l):
    if **len[l]** > 5:
        return [l]

len is builtin method it should be len(l)

Upvotes: 0

Related Questions