영구적 기능: 강력한 Reduce

작성자Federico Kereki
일찍이 2009년 12월에 ES5(정식 명칭: ECMA-262 5th Edition는 몇 가지 새로운 기능과 방법을 포함하였다.함수식 프로그래밍(FP)의 관점에서 볼 때 가장 중요한 것은 삼중주(사중주?)다음과 같은 인력으로 구성됩니다.

  • .map(...) 한 수조를 순서대로
  • 주어진 함수를 각 요소에 적용하여 한 수조를 다른 수조로 변환한다

  • .filter(...) 주어진 조건을 충족시키는 수조원소를 선택
  • 와 우리가 여기서 연구할 강력한 방법의 두 가지 버전: .reduce(...).reduceRight(...).이 함수들은 하나의 조작을 전체 그룹 (왼쪽에서 오른쪽 또는 오른쪽에서 왼쪽) 에 적용하여 하나의 결과로 줄인다.
  • 이 모든 것은 우리가 Forever Functional: Higher Order Functions -- Functions to rule functions 문장에서 이미 본 것처럼 '고급 함수' (HOF) 이다.여기서 정의한 바와 같이 HOF는 하나 이상의 함수를 매개 변수로 하는 함수입니다.위에서 열거한 모든 방법은 이 점을 만족시킬 것입니다. 이 방법을 사용하면 코드를 더욱 성명적인 방식으로 작성할 수 있습니다.예를 들어 수조에서 일부 요소를 선택하려면 순환을 작성하고 새로운 출력 수조를 초기화할 필요가 없다. 쓰기 yourArray.filter(someFunction) 를 하면 원시 수조의 모든 값을 포함하는 새 수조를 생성할 것이다. someFunction(...) 이 요소에 적용되면 이 값들은true를 생성할 것이다.결과를 생성하는 방법을 지정하는 것이 아니라 FP를 대상으로 작업을 수행하는 데 필요한 요소를 단계별로 설명합니다.
    흥미로운 것은 이 방법들 중 대다수가 사실상 쓸데없는 것이다.사실, 당신은 단지 하나: .reduce(...)!본문에서 우리는 그것을 어떻게 사용해서 형제를 모의하는지 연구할 것이다.이것은 우리로 하여금 그들의 내부 작업 원리를 깊이 이해하게 할 뿐만 아니라, 우리가 다른 곳에서 사용하기를 희망할 수도 있는 기술도 보게 할 것이다.우선 .reduce(...)의 작업 원리를 알고 다른 방법의 대체 방법으로 사용하자.

    배열을 값으로 축소

    .reduce(...)의 정상(추천) 사용 방식은 yourArray.reduce(someFunction, initialValue)와 유사하다.초기 값을 제공하는 것을 건너뛸 수 있지만, 오류가 발생할 수 있으니, 그러지 않는 것이 좋습니다. 어떻게 일을 줄일 수 있습니까?절차는 다음과 같습니다.
  • initialValue
  • 초기화 누적기 사용
  • 설치 누적기 = someFunction(누적기, 배열[0])
  • 그리고 누적기를 설정합니다=someFunction(누적기, 수조[1])
  • 그리고 누적기 = someFunction(누적기, 수조[2])
  • ...마지막 요소까지 모든 그룹을 순서대로 옮겨다니며 같은 동작을 실행합니다.
  • 아주 유명한 예: 만약 숫자가 있는 그룹이 있다면, 쓰기 yourArray.reduce((x,y)=>x+y, 0) 를 통해 그것들을 한 줄에 추가할 수 있다.누적기는 0에서 시작됩니다.그리고 그룹의 모든 연속 요소가 추가됩니다.최종 결과는 수조의 모든 원소의 총체가 될 것이다.이런 방식으로 일하면 "off-by-one" errors의 모든 가능성을 피할 수 있고 처리 초기화와 결과 처리가 가능하며 부작용이 없다.(우리는 Forever Functional: Injecting for Purity의 글에서 부작용이 없는 순함수를 토론했다.)

    In usual FP-speak, .reduce(...) is known as "fold" or possibly "foldl" ("fold left") and .reduceRight(...) is "foldr" ("fold right").


    현재.reduce(...)가 모든 다른 방법을 모방하기에 충분한지 뚜렷하지 않을 수도 있다.그럼 가장 간단한 상황부터 오른쪽에서 왼쪽으로 줄여봅시다.

    오른쪽에서 줄여주세요.

    .reduce(...)의 형제자매.reduceRight(...)는 일하는 방식이 완전히 같지만 처음부터 끝까지 수조를 두루 훑어보지 않고 수조의 끝에서부터 수조의 시작으로 돌아간다.많은 일(예를 들어 우리가 위에서 한 대수조에 대한 구화)에 대해 이것은 별 차이가 없지만, 다른 상황에서는 차이가 있을 수 있다.우리는 어떻게 이런 방법을 모방합니까?이것은 매우 쉽다!
    우리가 말한 바와 같이 유일한 차이점은 수조는 오른쪽에서 왼쪽으로 순서대로 처리된다는 것이다...그래서 가장 간단한 해결 방안은 (첫째) 반전수조를 한 값으로 줄이는 것이다!우리는 거의 방정식을 쓸 수 있다. yourArray.reduceRight(someFunction, initialValue) === yourArray.reverse().reduce(someFunction, initialValue).하지만 문제가 하나 있다.보이시나요?
    여기서 무슨 일이 있었죠?관건은 .reverse(...) 변이 방법이다. 그것은 실제로 수조를 반전시켰다.그래서 이런 식으로 일하면 우리는 똑같은 최종 결과를 얻을 것이다...그러나 우리도 예상치 못한 부작용을 일으킬 것이다. 수조는 반전될 것이다!정확한 방법은 먼저 수조의 부본을 생성하는 것이다.우리는 마땅히 써야 한다
    yourArray.reduceRight(someFunction, initialValue) === 
    [...yourArray].reverse().reduce(someFunction, initialValue)
    
    그래, 우리는 왜 이 판본을 사용해야 합니까?간단한 대답: 우리는 할 줄 몰라!우리가 원하는 결론은 .reduce(...) 자체가 대체품을 모방할 수 있다는 것이다.reduceRight(...)...그러나 이런 상황에서 해결 방안은 이 문제에 가치가 없는 것 같다!우리가 말한 바와 같이 이것은 더욱 횡적 사고방식의 연습이 되고 새로운 업무 방식을 찾을 것이며 목적지가 아니라 방식에 관한 것이 될 것이다.이제 다른 방법을 봅시다.

    매핑 배열


    원소 목록을 옮겨다니며 어떤 변환을 실행하는 것은 알고리즘에서 매우 흔히 볼 수 있는 모델이다.프로그래밍을 배우기 시작할 때, 이러한 순환을 작성하는 것은 기본적인 작업이다.우리는 당연히 for(...)문구로 이런 방식으로 수조를 처리할 수 있지만 .map(...)문구는 우리로 하여금 더욱 성명적인 방식으로 기능적으로 일하게 한다.흔히 볼 수 있는 예: firstNamelastName의 속성을 가진 일련의 사람들을 통해 우리는 다음과 같은 속성을 가진 모든 전명을 생성할 수 있다.
    let fullNames = persons.map((p) => p.firstName + " " + p.lastName);
    
    yourArray.map(aFunction) 을 썼을 때, 결과는 aFunction(...) (맵 함수) (맵 함수) 가 그룹의 모든 요소에 적용되어 새 그룹을 생성합니다.

    In math, a "map" is a transformation of values from a set into another one, like strings to numbers, objects to booleans, etc. In JavaScript, .map(...) transforms an array into a new one.


    우리는 .reduce(...)로 이 과정을 시뮬레이션할 수 있습니까?정답은 "네"입니다. 해결 방안은 매우 간단합니다.새 그룹을 만들려고 하는 것을 감안하여, 빈 그룹을 축소의 초기 값으로 하고, 맵 결과를 한 번에 추가합니다.
    const mapByReduce = (yourArray, aFunction) => yourArray.reduce((a, v) => a.concat(aFunction(v)), []);
    
    코드 좀 봅시다.우리는 빈 그룹부터 시작한다.수조의 모든 원소v는 함수의 매개 변수로 제시되었고 그 결과는 수조a에 연결되었다.생성된 어레이는 애플리케이션.map(...)과 동일한 결과를 얻을 수 있습니다.reduce(...).우리는 mapByReduce(...) 함수로 작성할 것입니다. 그러나 우리가 원한다면 Array.prototype 에 추가할 수 있습니다. 그런데 왜 이렇게 해야 합니까?우리는 몇 가지 방법에 대한 우리의 이해를 높이기 위해 새로운 실현을 연구하고 있다. (내가 말해야 할 것은 전혀 필요없는 것이다.) 그것들을 대체하는 것이 아니라.이제 마지막 방법을 생각해 봅시다. 여과.

    오픈 소스 세션 재방송


    생산 환경에서 웹 응용 프로그램을 디버깅하는 것은 어렵고 시간도 소모될 수 있다.OpenReplay는 풀스토리, 로그 로켓과 Hotjar의 소스 대체품이다.사용자가 한 모든 것을 감시하고 재방송할 수 있으며, 모든 문제에 대한 응용 프로그램의 표현을 보여 줍니다.
    이것은 브라우저의 검사기를 열고 사용자의 어깨를 보는 것과 같다.
    OpenReplay는 현재 유일하게 사용할 수 있는 오픈 소스 대안입니다.

    즐거움 디버깅, 현대 전단 팀-Start monitoring your web app for free.

    필터 배열


    필터 그룹은 어느 정도 매핑과 유사하다. 함수는 그룹의 모든 요소에 적용되기 때문이다. 그러나 이런 상황에서 그 사용 방식은 다르다. 함수가'truthy'값을 생성하면 해당하는 요소를 선택하여 결과에 추가한다."falsy"인 경우 요소가 제외됩니다.예를 들어 이전 예시와 같은 인원수 그룹에 대해 모든 사람이 age 속성을 가지고 있다면 우리는 성인을 쉽게 선택할 수 있다.
    let adults = persons.filter((p) => p.age >= 21);
    
    우리는 어떻게 해야만 이 점을 본받을 수 있습니까?이 해결 방안은 매핑과 유사하다.모든 요소에 필터 함수를 적용한 다음, 이 함수에 실제 값이 발생할 때만 결과에 추가합니다.
    const filterByReduce = (yourArray, aFunction) => yourArray.reduce((a, v) => (aFunction(v) ? a.concat(v) : a), []);
    
    함수의 결과에 따라, 우리는 삼원 연산자를 사용하여 수조의 원시 요소를 최종 결과에 추가할지 여부를 결정한다.다시 한 번, 우리는 .reduce(...)의 기능이 강하다는 것을 보았기 때문에 당신은 그것을 유일한 도구로 사용할 수 있습니다. 분명히 다른 방법이 이미 존재하기 때문에 당신은 이렇게 하고 싶지 않습니다!

    요약


    본고에서 우리는 몇 가지 기본적인 FP 방법을 고려했다. 우리는 그 중 하나인 Reduce를 보았는데 모든 다른 방법을 모방할 만큼 강력했다.그러나 이것은 단지 연습일 뿐이다. 왜 바퀴를 재발명해야 합니까?세부적인 것은, 우리는 이미 재미있는 기술을 응용했고, 어떻게 원시적인 방식으로 Reduce를 사용하는지에 대한 지식을 더 많이 배웠기 때문에, 당신은 당연히 그것을 자신의 코드에 응용할 수 있다.

    좋은 웹페이지 즐겨찾기