Python
.reduce()
from functools import reduce
Python3 이후, fuction ---> functools 로 변경되었습니다.
매서드 풀이
기본형
reduce(집계함수, 순회 가능한 데이터, 초기값)
기본적으로 위와 같습니다. 보통 누적 덧셈으로 reduce를 처음 접하고 이후 다양한 함수들을 연습해보면 좋습니다 !
반환값 :
설정한 함수의 return 값
예제 1. 누적 덧셈
from functools import reduce
arr = [1,2,3,4,5,6,7,8,9,10]
SUM1 = reduce(lambda x,y : x+y, arr)
SUM2 = reduce(lambda x,y : x+y, arr, 0)
print(SUM1)
print(SUM2)
풀이 : reduce는 참 신기하게 움직입니다. 만약 초기값 (위 SUM2의 3번째 인자 = 0) 이 설정되어 있다면 처음에 x는 초기값으로 설정되고 y는 해당 배열(리스트)의 첫번째 요소가 됩니다. 그리고 x+y 라는 연산으로 0+1이 되고 이 값은 x에 다시 담깁니다. 즉, 연산이 끝난 값은 x라는 곳에 다시 담깁니다. 그리고 계속 반복을 하지요!
보통 acc, cur 라는 변수로도 많이 사용합니다. 아래 acc, cur의 뜻을 보시면 이해가 빠르게 되실겁니다.
acc = accumulation (누적) (=x)
cur = current (현재의) (=y)
초기값의 여부 ? => IMPORTANT !
위에서 SUM1은 초기값이 없습니다. 이 경우 리스트의 첫 번째 값을 x (acc) 누적값에 놓고 리스트의 두 번째 값을 y에 놓고 시작합니다. 초기값이 있고 없고는 특정 상황에 따라 값을 판가름하니 꼭 알아두시면 좋습니다.
SUM1 과 SUM2 의 흐름도 ↓↓ 를 자세히 살펴보시면 reduce의 원리(?)가 잘 나와 있습니다.
from functools import reduce
arr = [1,2,3,4,5,6,7,8,9,10]
# 초기값이 없는 경우
SUM1 = reduce(lambda x,y : x+y, arr)
x = 1 y = 2 (여기서 1+2가 되어 값을 x에 담음))
x = 3 y = 3
x = 6 y = 4
x = 10 y = 5
x = 15 y = 6
x = 21 y = 7
x = 28 y = 8
x = 36 y = 9
x = 45 y = 10
마지막 x값 : 55을 return
# 초기값이 있는 경우
SUM2 = reduce(lambda x,y : x+y, arr, 0)
x = 0 y = 1 초기값을 x에 담음 x+y = 1을 다시 x에 담기
x = 1 y = 2
x = 3 y = 3
x = 6 y = 4
x = 10 y = 5
x = 15 y = 6
x = 21 y = 7
x = 28 y = 8
x = 36 y = 9
x = 45 y = 10
마지막 x값 : 55을 return
초기값이 없는 경우 리스트의 첫 번째 값을 x에 담았기때문에 연산은 총 9번 (len(arr)-1) 이 수행되고 SUM2 의 경우 초기값이 있기 때문에 len(arr) ==10 번 수행됩니다.
예제 2. 다른 연산 사용해보기 / 곱셈 / 제곱 / 해시의 특정 key의 값만 더하기
from functools import reduce
arr = [1,2,3,4,5]
# 두 수의 곱셈의 누적
A = reduce(lambda x,y : x*y, arr)
print(A)
# 두 수의 제곱의 누적 (x가 1이되어 결국 1return)
B = reduce(lambda x,y : x**y, arr)
print(B)
# key 가 'age'인 값만 더하기
users = [
{'name': 'aaa', 'age': 10},
{'name': 'bbb', 'age': 20},
{'name': 'ccc', 'age': 30},
{'name': 'ddd', 'age': 40},
{'name': 'eee', 'age': 50},
]
C = reduce(lambda x,y : x+y['age'],users,0)
print(C)
예제 3. 함수로 만들어서 사용해보기
from functools import reduce
arr = [1,2,3,4,5]
Fn = lambda acc,cur : acc if(acc>cur) else cur
A = reduce(Fn, arr)
print(A)
arr2 = [100,1,1,1,1]
B = reduce(Fn, arr2)
print(B)
arr3 = [1,100,2,200,4]
C = reduce(Fn, arr3)
print(C)
acc, crr = x, y 와 같다 ! 변수명은 마음대로 할 수 있다. 만약 acc 가 cur보다 더 큰경우 acc에 acc값을 넣고 작다면 cur 값을 넣습니다. 세 가지 배열로 비교해보면 좀 더 이해하기 좋습니다.
예제 4. 코딩 테스트에 사용하기
오늘 푼 문제 중에 reduce , lambda를 적용하여 푼 문제가 있습니다.
백준 11399번 문제 :
인하은행에는 ATM이 1대밖에 없다. 지금 이 ATM앞에 N명의 사람들이 줄을 서있다. 사람은 1번부터 N번까지 번호가 매겨져 있으며, i번 사람이 돈을 인출하는데 걸리는 시간은 Pi분이다.
사람들이 줄을 서는 순서에 따라서, 돈을 인출하는데 필요한 시간의 합이 달라지게 된다. 예를 들어, 총 5명이 있고, P1 = 3, P2 = 1, P3 = 4, P4 = 3, P5 = 2 인 경우를 생각해보자. [1, 2, 3, 4, 5] 순서로 줄을 선다면, 1번 사람은 3분만에 돈을 뽑을 수 있다. 2번 사람은 1번 사람이 돈을 뽑을 때 까지 기다려야 하기 때문에, 3+1 = 4분이 걸리게 된다. 3번 사람은 1번, 2번 사람이 돈을 뽑을 때까지 기다려야 하기 때문에, 총 3+1+4 = 8분이 필요하게 된다. 4번 사람은 3+1+4+3 = 11분, 5번 사람은 3+1+4+3+2 = 13분이 걸리게 된다. 이 경우에 각 사람이 돈을 인출하는데 필요한 시간의 합은 3+4+8+11+13 = 39분이 된다.
줄을 [2, 5, 1, 4, 3] 순서로 줄을 서면, 2번 사람은 1분만에, 5번 사람은 1+2 = 3분, 1번 사람은 1+2+3 = 6분, 4번 사람은 1+2+3+3 = 9분, 3번 사람은 1+2+3+3+4 = 13분이 걸리게 된다. 각 사람이 돈을 인출하는데 필요한 시간의 합은 1+3+6+9+13 = 32분이다. 이 방법보다 더 필요한 시간의 합을 최소로 만들 수는 없다.
줄을 서 있는 사람의 수 N과 각 사람이 돈을 인출하는데 걸리는 시간 Pi가 주어졌을 때, 각 사람이 돈을 인출하는데 필요한 시간의 합의 최솟값을 구하는 프로그램을 작성하시오.
위의 문제를 풀 때 작은 수부터 정렬한 후, 인덱스를 점차 키워나가며 reduce를 사용해서 총 sum을 구할 수 있습니다.
정답 코드 :
from functools import reduce
n = int(input())
arr = list(map(int,input().split()))
arr.sort()
answer = 0
for i in range(len(arr)):
answer += reduce(lambda x,y : x+y, arr[:i+1])
print(answer)
* 물론 for를 사용해서 더 간단하게도 가능합니다! 저는 reduce 공부할겸 겸사겸사 위의 코드로 풀었습니다.
도움이 되셨기를 바라며 (✿◡‿◡)
'Python > 매서드 Method, 내장 함수 등 정리' 카테고리의 다른 글
[Python] 파이썬 zip() 매서드 사용법 (0) | 2021.06.16 |
---|---|
[python] 합집합, 교집합, 차집합, 대칭차, 다중 집합의 합집합, 교집합까지 총 정리 / 파이썬 중복 집합 (0) | 2021.06.15 |
[Python] math.gcd & math.lcm 최대공약수 최소공배수 한번에 쉽게 구하기 (0) | 2021.06.13 |
[Python]숫자, 문자열에 0 또는 다른문자 채우기 .zfill() .rjust() .ljust() .center() (0) | 2021.06.06 |
[Python] 파이썬 .join 총 정리 / 리스트를 문자열로 바꾸기 (0) | 2021.06.04 |
댓글