[python] 함수형 프로그래밍의 ‘fold’함수에 해당하는 ‘pythonic’은 무엇입니까?

Haskell에서 다음과 같은 것을 달성하는 가장 관용적 인 방법은 무엇입니까?

foldl (+) 0 [1,2,3,4,5]
--> 15

또는 Ruby에서 이에 상응하는 것 :

[1,2,3,4,5].inject(0) {|m,x| m + x}
#> 15

분명히 파이썬은 reduce위와 똑같이 폴드 구현 인 함수를 제공 하지만, 프로그래밍의 ‘pythonic’방식은 가능한 경우 lambda목록 이해를 선호하는 용어와 고차 함수 를 피하는 것이라고 들었습니다 . 따라서 reduce함수 가 아닌 Python에서 목록 또는 목록과 유사한 구조를 접는 선호하는 방법 reduce이 있습니까? 아니면 이것을 달성하는 관용적 방법입니까?



답변

배열을 합하는 Pythonic 방법은 sum. 다른 목적을 위해 때때로 reduce( functools모듈에서)와 모듈의 조합을 사용할 수 있습니다 operator. 예 :

def product(xs):
    return reduce(operator.mul, xs, 1)

그주의 reduce사실이다 foldl하스켈 측면에서. 폴드를 수행하는 특별한 구문도없고 내장도 없으며 foldr실제로 reduce비 연관 연산자와 함께 사용 하는 것은 잘못된 스타일로 간주됩니다.

고차 함수를 사용하는 것은 매우 비단뱀 적입니다. 함수와 클래스를 포함하여 모든 것이 객체라는 파이썬의 원칙을 잘 활용합니다. 람다가 일부 Pythonistas에 의해 눈살을 찌푸리는 것은 맞지만, 대부분 복잡해지면 읽기가 쉽지 않기 때문입니다.


답변

Haskell

foldl (+) 0 [1,2,3,4,5]

파이썬

reduce(lambda a,b: a+b, [1,2,3,4,5], 0)

분명히 그것은 요점을 설명하는 사소한 예입니다. 파이썬에서는 그냥 할 sum([1,2,3,4,5])것이고 심지어 Haskell 순수 주의자들도 일반적으로 선호 할 것 sum [1,2,3,4,5]입니다.

명백한 편의 기능이없는 사소하지 않은 시나리오의 경우 관용적 파이썬 접근 방식은 for 루프를 명시 적으로 작성하고 reduce또는 을 사용 하는 대신 가변 변수 할당을 사용 하는 것 fold입니다.

그것은 전혀 기능적인 스타일은 아니지만 “파이썬”방식입니다. Python은 기능적 순수 주의자를 위해 설계되지 않았습니다. 파이썬이 어떻게 작동하지 않는 관용적 파이썬인지 확인하려면 흐름 제어에 대한 예외를 선호하는 방법을 참조하십시오.


답변

Python 3에서는 reduce이 제거되었습니다. 릴리스 정보 . 그럼에도 불구하고 functools 모듈을 사용할 수 있습니다.

import operator, functools
def product(xs):
    return functools.reduce(operator.mul, xs, 1)

반면에 문서는 for대신 -loop에 대한 선호를 표현 reduce하므로 다음과 같습니다.

def product(xs):
    result = 1
    for i in xs:
        result *= i
    return result


답변

휠을 재발 명 할 수도 있습니다.

def fold(f, l, a):
    """
    f: the function to apply
    l: the list to fold
    a: the accumulator, who is also the 'zero' on the first call
    """
    return a if(len(l) == 0) else fold(f, l[1:], f(a, l[0]))

print "Sum:", fold(lambda x, y : x+y, [1,2,3,4,5], 0)

print "Any:", fold(lambda x, y : x or y, [False, True, False], False)

print "All:", fold(lambda x, y : x and y, [False, True, False], True)

# Prove that result can be of a different type of the list's elements
print "Count(x==True):",
print fold(lambda x, y : x+1 if(y) else x, [False, True, True], 0)


답변

질문에 대한 답은 아니지만 foldl 및 foldr에 대한 한 줄 :

a = [8,3,4]

## Foldl
reduce(lambda x,y: x**y, a)
#68719476736

## Foldr
reduce(lambda x,y: y**x, a[::-1])
#14134776518227074636666380005943348126619871175004951664972849610340958208L


답변

시작 Python 3.8할당 표현식 소개 (PEP 572) (:= 연산자) 결과의 이름을 지정할 수 있습니다. 목록 이해를 사용하여 다른 언어에서 fold / foldleft / reduce 작업을 호출하는 것을 복제 할 수 있습니다.

목록, 축소 함수 및 누산기가 제공됩니다.

items = [1, 2, 3, 4, 5]
f = lambda acc, x: acc * x
accumulator = 1

우리는 접을 수 itemsf결과를 얻기 위해 accumulation:

[accumulator := f(accumulator, x) for x in items]
# accumulator = 120

또는 응축 된 형태 :

acc = 1; [acc := acc * x for x in [1, 2, 3, 4, 5]]
# acc = 120

목록 이해의 결과는 각 단계의 누적 상태를 나타내므로 실제로 “scanleft”작업이기도합니다.

acc = 1
scanned = [acc := acc * x for x in [1, 2, 3, 4, 5]]
# scanned = [1, 2, 6, 24, 120]
# acc = 120


답변

이 (줄이기) 문제에 대한 실제 대답은 : 그냥 루프를 사용하십시오!

initial_value = 0
for x in the_list:
    initial_value += x #or any function.

이것은 감소보다 빠르며 PyPy와 같은 것들은 루프를 최적화 할 수 있습니다.

BTW, 합계 케이스는 sum함수 로 해결해야 합니다.