L.map, L.filter take reduce 함수는 아래를 참고하자.
// L.range, L.map, L.filter, take
### L.range, L.map, L.filter, take, reduce 중첩 사용
<script>
const reduce = curry((f, acc, iter) => {
if (!iter) {
iter = acc[Symbol.iterator]();
acc = iter.next().value;
} else {
iter = acc[Symbol.iterator]();
}
let cur;
while (!(cur = iter.next()).done) {
const a = cur.value;
acc = f(acc, a);
}
return acc;
});
const take = curry((l, iter) => {
let res = [];
iter = iter[Symbol.iterator]();
let cur;
while (!(cur = iter.next()).done) {
const a = cur.value;
res.push(a);
if (res.length == l) return res;
}
return res;
});
L.range = function* (l) {
let i = -1;
while (++i < l) {
yield i;
}
};
L.map = curry(function* (f, iter) {
iter = iter[Symbol.iterator]();
let cur;
while (!(cur = iter.next()).done) {
const a = cur.value;
yield f(a);
}
});
L.filter = curry(function* (f, iter) {
iter = iter[Symbol.iterator]();
let cur;
while (!(cur = iter.next()).done) {
const a = cur.value;
if (f(a)) {
yield a;
}
}
});
go(L.range(10),
L.map(n => n + 10),
L.filter(n => n % 2),
take(2),
log);
</script>
find함수는 take를 통해서 결론을 지어서 만들 수가 있다.
예를 들어서 아래와 같은 데이터가 있다고 하자. users의 나이가 있다고 하자.
const users = [
{ age: 32 },
{ age: 31 },
{ age: 30 },
{ age: 29 },
{ age: 28 },
{ age: 27 }
];
usersd에서 첫번째로 특정조건을 만족하는 해당객체를 뽑아내는 함수가 find함수 일텐데 find함수를 간단하게 기존의 함수를 통해서 만들어 본다.
find함수는 함수를 받고 iter 이터러블을 받고 받은 객체에 iter로 시작을 해서 filter를 하고 받은 함수를 그대로 적용한다.
user의 나이가 30세 보다 적은 것을 뽑아본다고 log를 찍어보면 일단 모든 유저를 뽑고 있는데
<script>
const users = [
{ age: 32 },
{ age: 31 },
{ age: 30 },
{ age: 29 },
{ age: 28 },
{ age: 27 }
];
const find = (f, iter) => go(
iter,
filter(f)
);
log(find(u => u.age < 30, users));
</script>
find는 첫번째로 만나는 하나의 값만 계속해서 꺼내주는 함수이다. take를 해서 하나만 나오도록 하고 배열을 깨서 주는 함수를 추가로 넣어서 아래와 같이 만들 수 있다. 즉 처음으로 만난 30세보다 나이가 적은 객체를 꺼내었다.
const users = [
{ age: 32 },
{ age: 31 },
{ age: 30 },
{ age: 29 },
{ age: 28 },
{ age: 27 }
];
const find = (f, iter) => go(
iter,
filter(f),
take(1),
([a]) => a
);
log(find(u => u.age < 30, users));
// {age: 29}
하지만 이 find함수는 아쉬운 점이 있는데 a가 있고 함수에 a를 적용하는데 콘솔을 찍어서 확인을 해보고 결과를 전달해 준다면 하나의 결과만 take가 꺼내지만 모두 돌고 있는 것을 볼 수 있다.
const find = (f, iter) => go(
iter,
filter(a => (console.log(a), f(a))),
take(1),
([a]) => a
);
log(find(u => u.age < 30, users));
똑같은 함수를 넣어서 확인을 하면 세 객체를 만들어서 리턴하고 있다.
const find = (f, iter) => go(
iter,
filter(a => (console.log(a), f(a))),
a => (console.log(a), a),
take(1),
([a]) => a
);
앞에 L.만 붙여주면 미뤄져 있는 결과를 주게되고 take의 안쪽에서 하나씩 꺼내보면서 해당하는 값을 하나 찾을 수 있는 때가 오면 거기서 멈추고 결과를 반환한다. 그래서 그냥 filter보다 take에게 결과를 미뤄서 하나의 값이 꺼내지면 더 이상 filter를 하지 않도록 미뤄주면 효율적인 코딩이 가능하다.
const find = (f, iter) => go(
iter,
L.filter(a => (console.log(a), f(a))),
a => (console.log(a), a),
take(1),
([a]) => a
);
log(find(u => u.age < 30, users));
find는 받은 모든값을 어떠한 조건으로 filtering을 하되 하나만 꺼내질 때까지만 filtering을 한 후에 구조분해를 해서 결과를 주는 함수이다. find함수 안쪽에서는 for문도 없고 iter 이터러블 객체를 해석하고 돌리고 if한 다음에 사이에서 리턴하고 하는 코드가 없기 때문에 굉장히 이해하기가 좋다.
이터러블을 넣어서 필터를 하다가 첫번째꺼 하나 찾아지면 구조분해해서 꺼내준다라고 해석해주면 된다.
<script>
const users = [
{ age: 32 },
{ age: 31 },
{ age: 30 },
{ age: 29 },
{ age: 28 },
{ age: 27 }
];
const find = (f, iter) => go(
iter,
L.filter(f),
take(1),
([a]) => a
);
log(find(u => u.age < 30, users));
</script>
// {age: 29}
그리고 curry를 이용해 커링을 통해서도 사용하기 좋게 할 수 있다.
const find = curry((f, iter) => go(
iter,
L.filter(f),
take(1),
([a]) => a));
log(find(u => u.age < 30)(users));
take함수를 통해서 find함수를 만들었고 find라는 함수는 결국 특정 값 하나를 꺼내는 함수이고 find로 가기전에 어떤 함수들을 filter조건으로 합성해놓고 하는 식으로 사용할 수 있다.
결국 find는 take를 통해서 이터러블 값을 받는 함수이기 때문에 아래와 같이 사용할 수도 있다.
즉 find가 먼저 받는 값이 이터러블이기 때문에 연산을 완료한 값을 주어도 사용이 가능하고
const find = curry((f, iter) => go(
iter,
L.filter(f),
take(1),
([a]) => a));
log(find(u => u.age < 30)(users));
go(users,
map(u => u.age),
find(n => n < 30),
log);
// 29
결과를 미뤄넣은 채로 줘도 L.filter에서 받아서 한번 더 미룬 후에 take(1)에서 연산을 하면서 결과를 만들 수가 있다.
const find = curry((f, iter) => go(
iter,
L.filter(f),
take(1),
([a]) => a));
log(find(u => u.age < 30)(users));
go(users,
L.map(u => u.age),
find(n => n < 30),
log);
// 29
<출처 : 유인동 함수형 프로그래밍과 JavaScript ES6+>
https://www.inflearn.com/course/functional-es6/dashboard
함수형 프로그래밍과 JavaScript ES6+ - 인프런 | 강의
ES6+와 함수형 프로그래밍을 배울 수 있는 강의입니다. 이 강좌에서는 ES6+의 이터러블/이터레이터/제너레이터 프로토콜을 상세히 다루고 응용합니다. 이터러블을 기반으로한 함수형 프로그래밍,
www.inflearn.com
'JavaScript > 함수형 프로그래밍과 JavaScript ES6+' 카테고리의 다른 글
L.flatten, flatten (0) | 2021.08.24 |
---|---|
L.map L.filter로 map과 filter 만들기 (0) | 2021.08.24 |
Array.prototype.join 보다 다형성이 높은 join 함수 (0) | 2021.08.24 |
결과를 만드는 함수 reduce, take (0) | 2021.08.24 |
range, map, filter, take, reduce 중첩 사용(개발자도구로 순서확인) (0) | 2021.08.20 |