-
함수형 프로그래밍(ES5)-3.컬렉션 중심 프로그램 (1,2,3)카테고리 없음 2022. 4. 18. 21:52
-컬렉션 중심 프로그래밍
: 컬랙션을 잘 다루는 함수 세트들을 구성하는 식으로 프로그래밍해나가는걸 컬렉션 중심 프로그래밍이라고 함
컬렉션 : 배열, 리스트와 같은 돌림직한 데이터를 다루는 것
ex ) map, reduce, filter
4가지 유형으로 나누면
1. 수집하기 - map, values, pluck
2. 거르기 - filter, reject, compact, without
3. 찾아내기 - find, some, every
4. 접기(축약) - reduce, min, max, group_by, count_by
대표함수 : 각 유형의 모든 함수 중 추상화 레벨이 가장 높은 함수 => 대표함수로 각 유형의 특화함수를 만들 수 있다.
-컬렉션 중심 프로그래밍의 유형별 함수 만들기
var users = [ { id: 10, name: 'ID', age: 36 }, { id: 20, name: 'BJ', age: 32 }, { id: 30, name: 'JM', age: 32 }, { id: 40, name: 'PJ', age: 27 }, { id: 50, name: 'HA', age: 25 }, { id: 60, name: 'JE', age: 26 }, { id: 70, name: 'JI', age: 31 }, { id: 80, name: 'MP', age: 23 }, { id: 90, name: 'FP', age: 13 } ];
1. 수집하기 - map -> values, pluck
function _map(list, mapper) { const new_list = []; for (let i = 0; i < list.length; i++) { new_list.push(mapper(list[i])); } return new_list; } console.log( _map(users, function(users) { return users.name; }) ) 결과 : (9) ["ID", "BJ", "JM", "PJ", "HA", "JE", "JI", "MP", "FP"]
-> 내부 값 수집
1-1 values 함수 : object의 값들을 꺼내는 함수 (배열인 경우 input, output이 같아 의미 없음)
const object1 = { a: 'somestring', b: 42, c: false }; console.log(Object.values(object1)); // expected output: Array ["somestring", 42, false] //참조 https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/values
-map으로 values 만들기
function _values(data) { return _map(data, function(val) {return val;}); } console.log(users[0]) //{id: 10, name: "ID", age:36} console.log(_values(users[0])) //{10, "ID", 36} console.log(_keys(users[0])) //{"id", "name", "age"}
-_identity함수로 대체
function _values(data) { return _map(data, _identity) } function _identity(val) { return val }
1-2. pluck : 객체의 key 에 대한 값을 수집하는 함수 (간결함, 실용적!)
_pluck(users, 'age'); //[33, 22, 11, ...]
function _pluck(data, key) { return _map(data, function(obj) { return obj[key]; }) } function __pluck(data, key) { return _map(data, _get(key)); }
console.log(_pluck(users, 'age')) //[36, 32, 32, 27, 25, 26, 31, 23, 13]
2. 거르기 - filter -> reject, compact
-filter : 조건에 true인 값만 꺼내기
function _filter(list, predi) { const new_list = []; _each(list, function(val) { if (predi(val)) new_list.push(val); }); return new_list; }
console.log( _filter(users, function(user) { return user.age >30; }) )
2.1 reject : filter와 반대로 조건에 true인 값 제외시키는 함수
function _reject(data, predi){ return _filter(data, function(val){ return !predi(val) }) }
- predi 부분 함수화
function _negate(func){ return function(val){ return !func(val); } }
-간결해짐!
function _reject(data, predi){ return _filter(data, _negate(predi)); }
2.2 compact 함수 : 정의되지 않은 값 (null)이 없는 새 배열을 반환하는 함수
var _filter = _curryr(_filter); var _compact = _filter(_identity); console.log(_compact([1, 2, 0, false, null, {}])); // [ 1, 2, {} ]
컬렉션을 다루는 다양하고 서로 다른 함수 세트를 다양하게 구성하는게 컬렉션 중심의 프로그래밍 목표!
3. 찾아내기 - find : 배열에서 조건에 맞는 첫번째 값 리턴하는 함수 / find_index 조건에 맞는 첫번째 값 인덱스
(filter는 조건과 맞는 모든 값 / find는 첫번째 값)
3.1 find 함수 만들기
function _find(list, predi) { var keys = _keys(list); for (var i = 0, len = keys.length; i < len; i++) { const val = list[keys[i]]) if(predi(val)) return val; } }
console.log( _find(users, function(user) { return user.age < 30; }) ) // {id: 40, name: "PJ", age: 27} console.log( _find(users, function(user) { return user.id == 20; }) )
find 함수는 filter와 달리 첫번째 값만 리턴하는 함수이기 때문에 원하는 값을 찾으면 배열을 빠져나올 수 있는 최적화가 특징!
3.2 index_of
function _find_index(list, predi) { var keys = _keys(list); for (var i = 0, len = keys.length; i < len; i++) { if(predi(list[keys[i]]))) return i; } }
_get 함수 사용
console.log( _get(_find(users, function(user) { return user.id == 50; }), 'name'); ); // HA
_curryr 함수 사용
var _find = _curryr(function(list, predi) { var keys = _keys(list); for (var i = 0, len = keys.length; i < len; i++) { const val = list[keys[i]]) if(predi(val)) return val; } }) _go(users, _find(function(user) { return user.id == 50; }), _get('name'), console.log ) // HA
3.3 some : 하나의 조건이라도 만족하면 true를 리턴
_some([1, 2, 5, 10, 20], function(val) { return val > 10; }); // true
find_index함수로 만들기
function _some(data, predi) { return _find_index(data, predi) != -1 }
console.log(_some([1,2,5,10,20], function(val) { return val > 20; })) //false console.log(_some([1,2,5,10,20], function(val) { return val > 10; })) //true
3.4 every : 모든 값이 조건에 만족해야 true를 리턴
_every([1, 2, 5, 10, 20], function(val) { return val > 10; }); // false
function _every(data, predi) { return _find_index(data, _negate(predi)) == -1; }
console.log(_every([1,2,5,10,20], function(val) { return val > 20; })) //false console.log(_every([12,23,54,12,20], function(val) { return val > 10; })) //true
predi 없이 사용하기
console.log( _some([1,2,0,20],_identity) ) //true console.log( _some([null, false, 0],_identity) ) //false
function _some(data, predi) { return _find_index(data, _negate(predi || _identity)) == -1; } function _every(data, predi) { return _find_index(data, _negate(pred || _identity)) == -1; }
console.log( _some(users, function(user) { return user.age < 20 }) ) //true
console.log(_some([1,2,5,10,20], function(val) { return val > 20;})) //고차함수 보조함수
앞에 있는 고차함수를 고르고, 보조함수로 맵핑하면서 프로그래밍 하는것은 로직을 고르는 것과 같다!
-> 로직을 조합해 나가는 방식으로 프로그래밍하기