2017-05-19 2 views
2

Python3에서, 한 행lambda에서 함수를 두 개씩 호출하는 방법을 찾고 있습니다.Python3에서 one-liner reduce

print reduce(lambda a,b: a * b // gcd(a, b), mylist) 

가 1 행 Python3에서 동일한 작업을 수행하는 것이 가능 (암시 functools.reduce없이)의 난이이 one line in Python2 수행 할 수 있습니다 정수의 목록의 LCM를 계산하고 싶은 말은하자?

파이썬 3에서는 나는 filter, mapreduce이 없어 졌음을 안다. 더 짧고 더 명확한 방식으로 Python3로 작성 될 수 있기 때문에 나는 filtermap을 더 이상 필요로하지 않는다고 느낀다. 그러나 나는 아무 것도 찾지 못한 것 외에는 reduce을위한 멋진 대체물을 찾을 수 있다고 생각했다. 나는 have을 보았습니다 many 기사 that 을 사용하십시오 functools.reduce 또는 "write out the accumulation loop explicitly"을 사용하십시오. 그러나 functools를 가져 오지 않고 한 줄로하고 싶습니다.

더 쉽게 만들면 associativecommutative 인 함수를 사용해야 함을 언급해야합니다.

  • f(1,f(2,f(3,4)))
  • f(f(1,2),f(3,4))
  • f(f(3,f(1,4)),2)
  • 또는 다른 어떤 순서
+11

왜 한 줄로 바꾸고 싶습니까? 그리고,'functools.reduce'를 사용하고 싶지 않으십니까? 이 요구 사항들은 모두 임의적으로 보이고 실용적이지는 않다. –

+4

Chris의 의견에 덧붙이 기 위해'reduce'는 전역 네임 스페이스에서'functools'로 정확하게 옮겨졌습니다. 왜냐하면 * 간결한 (일부는 모호 할 수도 있음) one-liners . – Sneftel

+0

관련 : http://stackoverflow.com/questions/41524133/removing-duplicates-using-only-lambda-functions/41524134#41524134 –

답변

1

그래서를 : 그것은 하나가 계산하면 목록 [1,2,3,4]에 기능 f와 예를 들어, 결과가 좋은 것 나는 실제로 뭔가를 생각해 냈다. 나는 성능을 보장하지는 않지만 lambda 기능을 사용하는 1 라이너입니다. functools 또는 itertools의 기능은 아니며 단일 루프조차도 아닙니다. 그래서 여기가 전개되어

my_reduce = lambda l, f: (lambda u, a: u(u, a))((lambda v, m: None if len(m) == 0 else (m[0] if len(m) == 1 else v(v, [f(m[0], m[1])] + m[2:]))), l) 

이 다소 읽을 수 :

my_reduce = lambda l, f: (
    lambda u, a: u(u, a)) (
     (lambda v, m: None if len(m) == 0 
          else (m[0] if len(m) == 1 
             else v(v, [f(m[0], m[1])] + m[2:]) 
           ) 
     ), 
     l 
    ) 

테스트 :

>>> f = lambda a,b: a+b 
>>> my_reduce([1, 2, 3, 4], f) 
10 
>>> my_reduce(['a', 'b', 'c', 'd'], f) 
'abcd' 

이 어떻게 작동하는지에 대한 깊은 설명은 this other post을 확인하시기 바랍니다.

첫 번째 매개 변수가 함수 인 lambda 함수를 사용하여 재귀 함수를 에뮬레이트하는 것이 원칙이며 그 자체가됩니다.

이 재귀 함수는 효과적으로 재귀 호출을 트리거하는 함수 안에 포함됩니다. lambda u, a: u(u, a).

마지막으로 모든 것이 매개 변수가 목록 및 2 진 함수 인 함수에 래핑됩니다.당신은 적어도 하나 개의 항목으로 순서를 가정

my_reduce(mylist, lambda a,b: a * b // gcd(a, b)) 
+1

나는 Y combinator를 파열시키는 데 얼마나 오래 걸릴지 궁금해. I는 – Sneftel

+0

@Sneftel I가 @Sneftel가 참조 추측 [Y 연결자, 지정되지 않은 람다 계산법에 고정 소수점 연결자 하나 (https://en.wikipedia.org/wiki/Fixed-point_combinator# Fixed_point_combinators_in_lambda_calculus). ([비슷한 이름의 회사] (https://en.wikipedia.org/wiki/Y_Combinator_ (회사))와 혼동하지 마십시오. ([disambiguation] (https://en.wikipedia.org/wiki/Y_combinator))) –

+1

O_O 이해하지 –

1

는 당신이 간단하게 다음과 같이 재귀 적 reduce을 정의 할 수 있습니다 :

def reduce(func, seq): return seq[0] if len(seq) == 1 else func(reduce(func, seq[:-1]), seq[-1]) 

긴 당신의 코드를 사용하여


my_reduce 버전이 약간 더 읽기 쉬울 것입니다 :

def reduce(func, seq): 
    if len(seq) == 1: 
     return seq[0] 
    else: 
     return func(reduce(func, seq[:-1]), seq[-1]) 

그러나 이것은 재귀 적이며 파이썬은 재귀 호출 (reinsive calls)이 좋지 않습니다 (느린 의미와 재귀 제한은 300 개 항목보다 긴 시퀀스를 계산할 수 없게합니다). 훨씬 빠른 구현은 다음과 같습니다 :

def reduce(func, seq): 
    tmp = seq[0] 
    for item in seq[1:]: 
     tmp = func(tmp, item) 
    return tmp 

그러나 루프 때문에 한 줄에 입력 할 수 없습니다.

def reduce(func, seq): d = {}; [d.__setitem__('last', func(d['last'], i)) if 'last' in d else d.__setitem__('last', i) for i in seq]; return d['last'] 

나 : 그것은 부작용을 사용하여 해결할 수 빠르게 처리 될 수

def reduce(func, seq): 
    d = {} 
    for item in seq: 
     if 'last' in d: 
      d['last'] = func(d['last'], item) 
     else: 
      d['last'] = item 
    return d['last'] # or "d.get('last', 0)" 

있지만 목록 때문에 정확히 파이썬이 아니다 : 동등한입니다

def reduce(func, seq): d = {'last': seq[0]}; [d.__setitem__('last', func(d['last'], i)) for i in seq[1:]]; return d['last'] 

- 한 줄짜리 구현에서의 이해가 단지 부작용 때문에 사용됩니다.