V
V
Vlad2016-06-02 18:22:29
Python
Vlad, 2016-06-02 18:22:29

Why doesn't filter work as expected?

Hello.
There is the following code, which tells whether the given brackets (caps argument) are balanced in a string (source argument):

# Python 3.x
def is_balanced(source, caps):
    source = filter(lambda x: x in caps, source)
    caps = dict(zip(caps[::2], caps[1::2]))
    stack = []
    for cap in source:
        if stack and cap == caps.get(stack[-1], ""):
            stack.pop()
        else:
            stack.append(cap)
    return not stack

On a simple example,
is_balanced("(Sensei says yes!)", "()")
it returns False.
I ran through the lines in the debugger and found that the problem is that cap in the loop will never be equal to ")" o_o.
If we get rid of the iterator returned by the filter:
...
source = list(filter(lambda x: x in caps, source))
...

then everything works great.
And the question is: why is that? What? I do not understand?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
D
DeepBlue, 2016-06-02
@d1skort

The variable caps is overloaded: initially it means a string containing brackets, and then a dictionary. Because of this, filter, when executed on the "for cap in source:" line, checks if the character is among the keys of the dictionary, and not in the source line, and the closing bracket is not there. Name the dictionary differently and it will work:

def is_balanced(source, caps):
    source = filter(lambda x: x in caps, source)
    caps_dict = dict(zip(caps[::2], caps[1::2]))
    stack = []
    for cap in source:
        if stack and cap == caps_dict.get(stack[-1], ""):
            stack.pop()
        else:
            stack.append(cap)
    return not stack

A
Alexander, 2016-06-02
@fireSparrow

I wrote the answer and only then noticed that you changed the question a little. But I decided not to change the answer.
In the third line (where source is filtered), I wrapped the filter in a list().
Like this:
And everything worked for me.
I'm not sure, but I strongly suspect that this is the case:
filter() itself does not return a list, but an object of type "filter". That is, there is not yet the filtered sequence itself, but only instructions on what and how to filter.
And after that you change caps, which is involved in filtering. Accordingly, the filtering will take place in a different way.
I ran the filter a little on similar examples - it looks like my guess is correct.
If in the filter in the lambda we check the presence of a variable in the list, and then change the list, then the filter will work in a different way.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question