본문 바로가기

Study/VanillaJS

[개념잡기] 컬렉션 중심 프로그래밍 - (4) 접기 (min_by, max_by, group_by, count_by)

[개념잡기] 컬렉션 중심 프로그래밍 - (4) 접기 (min_by, max_by, group_by, count_by)

서론

reduce 함수를 이용하여 여러 축약 함수를 만들어보겠다.

var _reduce = function(list, iter, memo) {
  if(arguments.length == 2) {
    [memo, ...list] = list
  }
  _each(list, (val) => {
    memo = iter(memo, val)
  })
  return memo
}

console.log(
  _reduce([1,2,3,4], function(a, b){return a+ b})
) 
// 10

컬렉션 중심 프로그래밍

min

  • 기대동작 : 해당 오브젝트에서 가장 작은 값을 리턴
  • 코드 작성
var _min = (data) => {
  return _reduce(data, (a, b) => {
    return a < b ? a : b
  })
}

console.log(
  _min([1, 2, 3, 4, -1])
)
// -1

max

  • 기대동작 : 해당 오브젝트에서 가장 큰 값을 리턴
  • 코드 작성
var _max = (data) => {
  return _reduce(data, (a, b) => {
    return a > b ? a : b
  })
}

console.log(
  _max([1, 2, 3, 4, -1])
)
// 4

min_by

  • 기대동작 : min 함수와 동일하지만 특정 함수를 적용한 값중 최솟값을 리턴
  • 코드 작성
var _min_by = _curryr((data, iter) => {
  return _reduce(data, (a, b) => {
    return iter(a) < iter(b) ? a : b
  })
})

console.log(
  _min_by([2, 3, 4, 1, -11], Math.abs)
)
// 1

curryr 을 이용해 커리을 하였고 예제는 절댓값을 적용시킨 리스트의 최솟값을 출력하는 예제이다. 이러한 min_by 함수는 기존의 리스트의 값을 변경하지 않기 때문에 유용하다.

max_by

  • 기대동작 : max 함수와 동일하지만 특정 함수를 적용한 값중 최댓값을 리턴
  • 코드 작성
var _max_by = _curryr((data, iter) => {
  return _reduce(data, (a, b) => {
    return iter(a) > iter(b) ? a : b 
  })
})

console.log(
  _max_by([1, 2, 3, 4, -11], Math.abs)
)
// -11

절댓값이 가장 큰 -11이 리턴되었다.

group_by

  • 기대동작 : 오브젝트와 함수를 넣으면 해당 함수의 조건을 기준으로 그룹화한 오브젝트를 반환
  • 코드 작성
var users = [
  {id: 1, name: 'ID', age: 29},
  {id: 2, name: 'QW', age: 30},
  {id: 3, name: 'WE', age: 30},
  {id: 4, name: 'ER', age: 32},
  {id: 5, name: 'RT', age: 21},
  {id: 6, name: 'DF', age: 28},
  {id: 7, name: 'AS', age: 35},
  {id: 8, name: 'IS', age: 25}
]

var _push = (obj, key, val) => {
  (obj[key] = obj[key] || []).push(val)
  return obj
}

var _group_by = _curryr((data, iter) => {
  return _reduce(data, (grouped, val) => {
    return _push(grouped, iter(val), val)
  } ,{})
})

_go(
  users,
  _group_by(user => user.age),
  console.log
)

// 출력
{
  "21": [
    { "id": 5, "name": "RT", "age": 21 }
  ],
  "25": [
    { "id": 8, "name": "IS", "age": 25 }
  ],
  "28": [
    { "id": 6, "name": "DF", "age": 28 }
  ],
  "29": [
    { "id": 1, "name": "ID", "age": 29 }
  ],
  "30": [
    { "id": 2, "name": "QW", "age": 30 },
    { "id": 3, "name": "WE", "age": 30 }
  ],
  "32": [
    { "id": 4, "name": "ER", "age": 32 }
  ],
  "35": [
    { "id": 7, "name": "AS", "age": 35 }
  ]
}

users 데이터를 age를 기준으로 그룹화한 오브젝트가 반환되었다. push 함수는 검증된 push 를 하기위해 함수화하였다.

count_by

  • 기대동작 : 오브젝트와 함수를 넣으면 함수의 조건을 기준으로 해당하는 데이터를 카운트한 오브젝트를 반환
  • 코드 작성
var users = [
  {id: 1, name: 'ID', age: 29},
  {id: 2, name: 'QW', age: 30},
  {id: 3, name: 'WE', age: 30},
  {id: 4, name: 'ER', age: 32},
  {id: 5, name: 'RT', age: 21},
  {id: 6, name: 'DF', age: 28},
  {id: 7, name: 'AS', age: 35},
  {id: 8, name: 'IS', age: 25}
]

var _inc = (count, key) => {
  count[key] ? count[key]++ : count[key] = 1
  return count
}

var _count_by = _curryr((data, iter)=> {
  return _reduce(data, (count, val) => {
    return _inc(count, iter(val))
  }, {})
})

_go(
  users,
  _count_by(user => user.age),
  console.log
)

// 출력
{
  "21": 1,
  "25": 1,
  "28": 1,
  "29": 1,
  "30": 2,
  "32": 1,
  "35": 1
}

마무리

다음 포스팅에서 컬렉션 중심 프로그래밍 정리가 끝난다. 조금 실전에서 이용할수 있는 방법으로 포스팅하겠다.