How to use filter, map, and reduce in Python 3

前端 未结 7 1691
夕颜
夕颜 2020-11-22 08:27

filter, map, and reduce work perfectly in Python 2. Here is an example:

>>> def f(x):
        return x % 2 !=         


        
相关标签:
7条回答
  • 2020-11-22 08:56

    You can read about the changes in What's New In Python 3.0. You should read it thoroughly when you move from 2.x to 3.x since a lot has been changed.

    The whole answer here are quotes from the documentation.

    Views And Iterators Instead Of Lists

    Some well-known APIs no longer return lists:

    • [...]
    • map() and filter() return iterators. If you really need a list, a quick fix is e.g. list(map(...)), but a better fix is often to use a list comprehension (especially when the original code uses lambda), or rewriting the code so it doesn’t need a list at all. Particularly tricky is map() invoked for the side effects of the function; the correct transformation is to use a regular for loop (since creating a list would just be wasteful).
    • [...]

    Builtins

    • [...]
    • Removed reduce(). Use functools.reduce() if you really need it; however, 99 percent of the time an explicit for loop is more readable.
    • [...]
    0 讨论(0)
  • 2020-11-22 08:59

    As an addendum to the other answers, this sounds like a fine use-case for a context manager that will re-map the names of these functions to ones which return a list and introduce reduce in the global namespace.

    A quick implementation might look like this:

    from contextlib import contextmanager    
    
    @contextmanager
    def noiters(*funcs):
        if not funcs: 
            funcs = [map, filter, zip] # etc
        from functools import reduce
        globals()[reduce.__name__] = reduce
        for func in funcs:
            globals()[func.__name__] = lambda *ar, func = func, **kwar: list(func(*ar, **kwar))
        try:
            yield
        finally:
            del globals()[reduce.__name__]
            for func in funcs: globals()[func.__name__] = func
    

    With a usage that looks like this:

    with noiters(map):
        from operator import add
        print(reduce(add, range(1, 20)))
        print(map(int, ['1', '2']))
    

    Which prints:

    190
    [1, 2]
    

    Just my 2 cents :-)

    0 讨论(0)
  • 2020-11-22 09:00

    Since the reduce method has been removed from the built in function from Python3, don't forget to import the functools in your code. Please look at the code snippet below.

    import functools
    my_list = [10,15,20,25,35]
    sum_numbers = functools.reduce(lambda x ,y : x+y , my_list)
    print(sum_numbers)
    
    0 讨论(0)
  • 2020-11-22 09:15

    One of the advantages of map, filter and reduce is how legible they become when you "chain" them together to do something complex. However, the built-in syntax isn't legible and is all "backwards". So, I suggest using the PyFunctional package (https://pypi.org/project/PyFunctional/). Here's a comparison of the two:

    flight_destinations_dict = {'NY': {'London', 'Rome'}, 'Berlin': {'NY'}}
    

    PyFunctional version

    Very legible syntax. You can say:

    "I have a sequence of flight destinations. Out of which I want to get the dict key if city is in the dict values. Finally, filter out the empty lists I created in the process."

    from functional import seq  # PyFunctional package to allow easier syntax
    
    def find_return_flights_PYFUNCTIONAL_SYNTAX(city, flight_destinations_dict):
        return seq(flight_destinations_dict.items()) \
            .map(lambda x: x[0] if city in x[1] else []) \
            .filter(lambda x: x != []) \
    

    Default Python version

    It's all backwards. You need to say:

    "OK, so, there's a list. I want to filter empty lists out of it. Why? Because I first got the dict key if the city was in the dict values. Oh, the list I'm doing this to is flight_destinations_dict."

    def find_return_flights_DEFAULT_SYNTAX(city, flight_destinations_dict):
        return list(
            filter(lambda x: x != [],
                   map(lambda x: x[0] if city in x[1] else [], flight_destinations_dict.items())
                   )
        )
    
    0 讨论(0)
  • 2020-11-22 09:16

    The functionality of map and filter was intentionally changed to return iterators, and reduce was removed from being a built-in and placed in functools.reduce.

    So, for filter and map, you can wrap them with list() to see the results like you did before.

    >>> def f(x): return x % 2 != 0 and x % 3 != 0
    ...
    >>> list(filter(f, range(2, 25)))
    [5, 7, 11, 13, 17, 19, 23]
    >>> def cube(x): return x*x*x
    ...
    >>> list(map(cube, range(1, 11)))
    [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
    >>> import functools
    >>> def add(x,y): return x+y
    ...
    >>> functools.reduce(add, range(1, 11))
    55
    >>>
    

    The recommendation now is that you replace your usage of map and filter with generators expressions or list comprehensions. Example:

    >>> def f(x): return x % 2 != 0 and x % 3 != 0
    ...
    >>> [i for i in range(2, 25) if f(i)]
    [5, 7, 11, 13, 17, 19, 23]
    >>> def cube(x): return x*x*x
    ...
    >>> [cube(i) for i in range(1, 11)]
    [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
    >>>
    

    They say that for loops are 99 percent of the time easier to read than reduce, but I'd just stick with functools.reduce.

    Edit: The 99 percent figure is pulled directly from the What’s New In Python 3.0 page authored by Guido van Rossum.

    0 讨论(0)
  • 2020-11-22 09:16
    from functools import reduce
    
    def f(x):
        return x % 2 != 0 and x % 3 != 0
    
    print(*filter(f, range(2, 25)))
    #[5, 7, 11, 13, 17, 19, 23]
    
    def cube(x):
        return x**3
    print(*map(cube, range(1, 11)))
    #[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
    
    def add(x,y):
        return x+y
    
    reduce(add, range(1, 11))
    #55
    

    It works as is. To get the output of map use * or list

    0 讨论(0)
提交回复
热议问题