본문 바로가기
개발일지/JavaScript ES6

[1~5] 홀수 n개 더하기, if를 filter로, 값 변화 후 변수 할당을 map으로, break를 take로, 축약 및 합산을 reduce로 (+ 이터러블 프로그래밍과 리스트 프로세싱)

by 꾸주니=^= 2024. 11. 30.

1. 홀수 n개 더하기

홀수 n개 더하기 코드
<!-- 1. 홀수 n개 더하기 -->
    <script>
        function f1(limit, list){
            let acc = 0;
            for (const a of list){
                if (a % 2){
                    //제곱된 값 출력하기
                    const b = a*a;
                    acc += b;
                    //console.log(b);

                    //limit을 가지고 홀수가 3번 나올 때 까지만 출력하겠다.
                    if (--limit === 0) break;
                }
            }
            //모든 값 더하기
            console.log(acc);
        }
        f1(3,[1,2,3,4,5,6,7,8,9,10]);
    </script>

(1) 함수 정의
limit : 처리할 홀수의 최대 개수 -> 3
list  : 숫자 배열 -> [1,2,3,4,5,6,7,8,9,10]

(2) 배열 순회
for...of 문을 사용해 list 배열의 각 요소를 순회

(3) 홀수 판별
a % 2 는 a가 홀수 인지를 판별

  • 홀수 : a % 2 == 1 (참)
  • 짝수 : a % 2 == 0 (거짓)

(4) 제한된 개수의 홀수만 처리
--limit : limit 값을 1 감소시킨
limit === 0 : limit이 0이 되면 break문으로 for루프를 종료한다.

 


2. if를 filter로 적용하기

우선, 이터러블 프로그래밍과 리스트 프로세싱에 대해 알아보겠다.
이터러블 프로그래밍과 리스트 프로세싱은 데이터를 선언적으로 처리하는 프로그래밍 방식으로, 함수형 프로그래밍 패러다임과 밀접한 관계가 있다.

 

1. 이터러블 프로그래밍

이터러블 프로그래밍은 이터러블 객체(Iterable)를 중심으로 데이터를 처리하는 방식을 말한다.
이터러블 객체란, 반복 가능한 값의 집합이며, 배열, 문자열, 맵, 셋 등이 이에 해당한다.

  • 이터레이터(iterator): 이터러블 객체를 순회(iterate)하는 도구로, for...of문이나 next() 메서드로 요소를 하나씩 처리한다.
  • 이터러블 프로그래밍은 데이터를 "필터링", "변환", "축소" 등의 작업을 통해 점진적으로 처리한다.

 

2. 리스트 프로세싱 (Lisp)

리스트 프로세싱은 데이터를 리스트 형태로 처리하는 방식으로, 함수형 프로그래밍 언어에서 기원했다.
핵심은 데이터를 변형하거나 필터링하는 작업을 선언적으로 표현하는 것이다.
Lisp에서는 데이터를 "필터(filter)", "맵(map)", "축소(reduce)" 같은 함수로 처리한다.

  • Declarative (선언형): 작업을 "어떻게"가 아니라 "무엇"을 해야 하는지를 코드로 표현한다.
  • Lazy Evaluation (지연 평가): 필요한 값만 계산하며, 메모리 효율성을 높인다.

 

L.filter 코드

이 코드는 이터러블 프로그래밍의 L.filter과 지연 평가를 활용해 배열에서 홀수의 제곱 값을 계산하고, 특정한 개수만 처리하여 합계를 구한다.

<!-- 이터러블 프로그래밍 혹은 리스트 프로세싱 (Lisp) 적용해보기 -->
    <!-- 2. if를 filter로 -->
    <script>
        function f2(limit, list){
            let acc = 0;

            //if문을 L.filter로 대체해보기
            for (const a of L.filter(a => a % 2, list)){
                const b = a*a;
                acc += b;
                    
                if (--limit === 0) break;
            
            }
            console.log(acc);
        }
        f2(3,[1,2,3,4,5,6,7,8,9,10]);
    </script>

[L.filter를 이용한 필터링]
     : L.filter: 배열의 요소 중 조건을 만족하는 값만 필터링한다.

  • (a => a % 2): 홀수만 통과하도록 하는 조건.
  • list는 [1,2,3,4,5,6,7,8,9,10]입니다.
  • 결과: 1, 3, 5, 7, 9.

 


L.filter 작동 방식

L.filter를 통해서 list[1,2,3,4]를 value가 1,3만 꺼내지고 더이상 순회할게 없다고 메시지를 전달해줘서 리터럴을 반환해준다.

 

L.filter를 즉시 평가할 때 앞에 '...'붙이기

 

강의 코드 작동 결과

 


3. 값 변화 후 변수 할당을 map으로

map은 함수형 프로그래밍에서 주어진 함수를 사용하여 데이터를 변환하는 작업에 사용된다. 리스트(배열)와 같은 이터러블 객체의 각 요소에 대해 특정 연산을 수행하고, 그 결과를 새로운 이터러블로 반환한다.

L.map은 일반 map과 비슷하지만, 지연 평가(lazy evaluation)를 지원한다. 이터러블에서 필요한 순간에만 요소를 계산하므로 메모리 효율성이 높아진다.이터러블 프로그래밍에서는 map을 사용하여 추상화한다.

 

L.map

주어진 코드는 L.map을 사용하여 필터링된 리스트의 요소를 변환(제곱)한 뒤, 그 값을 누적합으로 계산한다.

    <!-- 이터러블 프로그래밍 혹은 리스트 프로세싱 (Lisp) 적용해보기 -->
    <!-- 3. 값 변화 후 변수 할당을 map으로 -->
    <script>
        function f2(limit, list){
            let acc = 0;
            for (const a of L.map(a => a * a, L.filter(a => a % 2, list))){
                acc += b;   
                if (--limit === 0) break;
            }
            console.log(acc);
        }
        f2(3,[1,2,3,4,5,6,7,8,9,10]);
    </script>

[L.map을 사용한 변환]

  • L.filter: 리스트에서 홀수만 선택.
    • a => a % 2: 홀수 조건.
    • 결과: [1, 3, 5, 7, 9].
  • L.map: 선택된 홀수의 각 요소를 제곱.
    • a => a * a: 각 홀수를 제곱.
    • 결과: [1, 9, 25, 49, 81].

 


4. break를 take로

take는 이터러블 프로그래밍에서 주어진 개수만큼의 값을 가져오는 데 사용된다. 리스트(또는 이터러블)에서 처음 N개의 값을 가져오고, 그 이후의 값은 계산하지 않으므로 메모리 효율적이다. 이는 특히 지연 평가(Lazy Evaluation)를 사용하는 경우에 유용하다.

L.take(limit, iterable): 이터러블에서 최대 limit개의 값을 가져온다.

 

L.take 코드

주어진 코드는 take를 사용하여 제곱된 값에서 처음 limit개의 값을 가져와 합계를 계산한다.

    <!-- 이터러블 프로그래밍 혹은 리스트 프로세싱 (Lisp) 적용해보기 -->
    <!-- 4. break를 take로 -->
    <script>
        function f2(limit, list){
            let acc = 0;
            for (const a of L.take(limit, L.map(a => a * a, L.filter(a => a % 2, list)))){
                acc += b;   
            }
            console.log(acc);
        }
        f2(3,[1,2,3,4,5,6,7,8,9,10]);
    </script>

[데이터 흐름]
filter → map → take

  • L.filter(a => a % 2, list)
    • 리스트에서 홀수만 필터링.
    • 예: [1, 3, 5, 7, 9].
  • L.map(a => a * a, ...)
    • 필터링된 값에 대해 제곱 계산.
    • 예: [1, 9, 25, 49, 81].
  • L.take(limit, ...)
    • limit(예: 3)개의 값만 가져옴.
    • 결과: [1, 9, 25]

 


L.take는 최대 limit까지만 값을 꺼내겠다. 위 사진에서는 limit=2

 


5. 축약 및 합산을 reduce로

어떠한 값이나 어떠한 함수로 축약 또는 합산하는 것을 reduce라고 한다.

 

 _.reduce (lodash의 reduce 함수)
_.reduce는 lodash 라이브러리의 함수로, 배열 또는 객체의 값을 축소(reduce)하여 하나의 값으로 만듬

 

reduce의 기본 작동 원리
- 배열의 각 요소를 순회하면서 누적(accumulator)을 계산한다.
- 초기값을 설정하고, 각 요소에 대해 지정된 함수를 실행하여 새로운 값을 반환한다.

 

_.reduce 사용 예 1
    <!-- 이터러블 프로그래밍 혹은 리스트 프로세싱 (Lisp) 적용해보기 -->
    <!-- 5. 축약 및 합산을 reduce로 -->
    <script>
        function f2(limit, list){
            console.log(
            _.reduce((acc,a) => acc + a,
                0, //0이 acc에 들어감.
                L.take(limit,
                    L.map(a => a * a,
                        L.filter(a => a % 2, list)))));
        }
        f2(3,[1,2,3,4,5,6,7,8,9,10]);
    </script>

 

_.reduce 사용 예 2

 

예제1,2 결과는 똑같음

 


이처럼 _.reduce는 훨씬 사람이 읽기 쉬운 코드라고 할 수 있다.

좀 더 읽기 쉽게 하기 위해서는 _.go를 사용해 순서를 반대로 하는 방법이 있다.