import * as R from 'ramda'
const array: number[] = [3,4]
const new_arr_p = R.prepend(1)(array)
const new_arr_a = R.append(1)(array)
console.log(new_arr_p)
console.log(new_arr_a)
실행결과
[ 1, 3, 4 ][ 3, 4, 1 ]
prepend는 배열의 앞쪽에 값을 추가하는것이고
append는 배별의 뒤쪽에 값을 추가하는 함수이다.
flatten 함수는 복잡한 배열을 평탄화 시켜주는 역할을 한다.
import * as R from 'ramda'
const arr = R.range(1,3).map((x: number) => {
return R.range(1,3).map((y: number) => {
return [x,y]
})
})
console.log(arr)
const flat_arr = R.flatten(arr)
console.log(flat_arr)
실행결과
[ [ [ 1, 1 ], [ 1, 2 ] ], [ [ 2, 1 ], [ 2, 2 ] ] ] ,
[
1, 1, 1, 2,
2, 1, 2, 2
]
보이는 대로 복잡한 배열을 저런식으로 평탄화 시킬 수 있다.
unnest 함수는 완벽하게 평탄화 시키지는 않고 좀 더 정교한 방식으로 배열을 평탄화 시킨다.
import * as R from 'ramda'
const arr = R.range(1,3).map((x: number) => {
return R.range(1,3).map((y: number) => {
return [x,y]
})
})
console.log(arr)
const unnest_arr = R.unnest(arr)
console.log(unnest_arr)
//@ts-ignore
const unnest_arr_R = R.pipe(R.unnest,R.unnest)(arr)
console.log(unnest_arr_R)
실행결과
[ [ [ 1, 1 ], [ 1, 2 ] ], [ [ 2, 1 ], [ 2, 2 ] ] ]
[ [ 1, 1 ], [ 1, 2 ], [ 2, 1 ], [ 2, 2 ] ][ 1, 1, 1, 2, 2, 1, 2, 2 ]
위와 같이 좀 더 정교하게 분해하는 모습을 볼 수 있다.
처음에는 한번만 돌리고 두번째는 두번 돌렸을때 결과이다.
sort는 이름에서 알 수 있듯이 배열을 오름차순이나 내림차 순으로 정렬해 주는 함수이다.
import * as R from 'ramda'
type voidToNumberFunc = () => number
const makeRandomNumber = (max: number): voidToNumberFunc =>
(): number => Math.floor(Math.random() * max)
const arr = R.range(1,6).map(makeRandomNumber(100))
const sortedArr = R.sort((a: number,b: number): number => a-b)(arr)
console.log(arr,sortedArr)
콜백에 마이너스 값이면 오름차순 0이나 플러스값이면 내림차 순이라고 하는데
무슨말인지 잘모르겠다. 이대로 실행하면 오름차순으로 정렬되어 나오긴한다.
좀더 보니깐 b-a로 하면 내림차순 구현이 된다.
배열에 담긴 아이템이 객체라면 특정 속성값에 따라 정렬해야하는데 이때
sortBy 함수를 사용한다.
import * as R from 'ramda'
import { IPerson,makeRandomIPerson } from './model/person'
import { displayPerson } from './displayPerson'
const persons: IPerson[] = R.range(1,5).map(makeRandomIPerson)
const nameSortedPersons = R.sortBy(R.prop('name'))(persons)
const ageSortedPersons = R.sortBy(R.prop('age'))(persons)
displayPerson('sorted by name')(nameSortedPersons)
displayPerson('sorted by age')(ageSortedPersons)
sortby-test.ts
import * as R from 'ramda'
import { IPerson } from './model/person'
export const displayPerson = (prefix: string) => R.pipe(
R.map((person: IPerson) => ({name: person.name,age: person.age})),
R.tap(o => console.log(prefix,o))
)as any
displayPerson.ts
실행결과
sorted by name [
{ name: 'Alejandro Beck', age: 41 },
{ name: 'Eleanor Colon', age: 18 },
{ name: 'Genevieve Bishop', age: 64 },
{ name: 'Troy Ward', age: 42 }
]
sorted by age [
{ name: 'Eleanor Colon', age: 18 },
{ name: 'Alejandro Beck', age: 41 },
{ name: 'Troy Ward', age: 42 },
{ name: 'Genevieve Bishop', age: 64 }
]
sortBy는 항상 오름차순으로만 정렬한다.
sortWith 함수는 ascend,descend를 이용해서 오름차순과 내림차순 정렬을 할 수있다.
import * as R from 'ramda'
import { IPerson,makeRandomIPerson } from './model/person'
import { displayPerson } from './displayPerson'
const persons: IPerson[] = R.range(1,5).map(makeRandomIPerson)
//@ts-ignore
const nameSortedPerson = R.sortWith([R.descend(R.prop(('name')))])(persons)
displayPerson('sorted by name')(nameSortedPerson)
람다 라이브러리 자체가 js기반이라 그런지는 모르겠는데
알 수 없는 오류가 자꾸 발생한다.
너무 화난다.
이런식으로 하면 내림차순으로 구현이된다.
애초에 뭐 공식사이트에 있는 예제를 박아도 똑같은 오류가 난다
chain 조합자는 함수를 매개변수로 받아 동작하는 함수로
매개변수가 한개일때와 두개일때의 동작이 다르다.
import * as R from 'ramda'
const array = [1,2,3]
R.pipe(
R.chain(n => [n,n]),
R.tap(n => console.log(n))
)(array)
R.pipe(
R.chain(R.append,R.head),
R.tap(n => console.log(n))
)(array)
실행결과
[ 1, 1, 2, 2, 3, 3 ][ 1, 2, 3, 1 ]
둘이 보면 실행결과가 다른데
매개변수가 한개일때는 아래 코드와 같이 동작한다.
import * as R from 'ramda'
const array = [1,2,3]
const flatMap = (f) => R.pipe(
R.map(f),
R.flatten
)
R.pipe(
flatMap(n => [n,n]),
R.tap(n => console.log(n))
)(array)
실행결과
[ 1, 1, 2, 2, 3, 3 ]
그리고 매개변수가 두개일때는 아래와 같이 동작한다.
import * as R from 'ramda'
const array = [1,2,3]
const chainTwoFunc = (firstFn,SecondFn) => (x) => firstFn(SecondFn(x),x)
R.pipe(
chainTwoFunc(R.append,R.head),
R.tap(n => console.log(n))
)(array)
실행결과
[ 1, 2, 3, 1 ]
flip 함수는 2차 고차 함수의 매개변수 순서를 서로 바꿔주는 역할을 한다.
const flip = cb => a => b => cb(b)(a)
import * as R from 'ramda'
const flip = cb => a => b => cb(b)(a)
const reverseSubtract = flip(R.subtract)
const new_arr = R.pipe(
R.map(reverseSubtract(10)),
R.tap(n => console.log(n))
)(R.range(1,10))
flip을 풀어서 구현했다.
identity는 엄청 단순하게 생겼다.
const identity = x => x
구조상 함수가 꼭 필요한 자리에 넣어줄 수 있는 조합자이다.
import * as R from 'ramda'
import { flatMap } from './flatmap'
const unnest = flatMap(R.identity)
const arr = [[1],[2],[3]]
R.pipe(
unnest,
R.tap(n => console.log(n))
)(arr)
flatMap 함수가 요구하는 콜백함수 자리에 identity를 넣은 모습을 볼 수 있다.
always 조합자는 두개의 고차함수 파라미터중 첫번째 파라미터를 반환한다.
const always = x => y => x
import * as R from 'ramda'
const always = a => b => a
const flip = cb => a => b => cb(b)(a)
const first = <T>(a: T) => (b: T): T => always(a)(b)
const second = <T>(a: T) => (b: T): T => flip(always)(a)(b)
console.log(
first(1)(2),
second(1)(2)
)
실행결과
1 2
flip은 파라미터의 순서를 바꿔준다
따라서 위와같은 실행결과가 나오게된다.
applyTo 조합자는 특별하게 값을 첫 번째 매개변수로 이값을 입력으로 하는 콜백 함수를 두 번째 매개변수로 받아 다음 코드처럼 동작한다.
뭐라는거지
const applyTo = value => cb => cb(value)
위와같은 방식으로 작용한다고 한다.
import * as R from 'ramda'
const T = value => R.pipe(
R.applyTo(value),
R.tap(value => console.log(value))
)
const value100 = T(100)
const sameValue = value100(R.identity)
const add1Value = value100(R.add(1))
실행결과
100 101
위와같은 방식으로 동작한다.
ap 조합자는 콜백 함수들의 배열을 첫 번째 매개변수로 배열을 두번째 매개변수로 입력받는 2차 고차 함수이다.
const ap = ([callback]) => arr => [callback] (arr)
ap 에 콜백함수가 하나일때는 map 처럼 동작한다.
import * as R from 'ramda'
const callAndAppend = R.pipe(
R.ap([R.multiply(2)]),
R.tap(n => console.log(n))
)
const input = [1,2,3]
const result = callAndAppend(input)
실행결과
[2,4,6]
하지만 콜백이 두개일때는
R.chain(n =>[n,n]) 처럼 동작한다.
두 개일때 두 콜백 함수를 적용한 각각의 배열을 만든 다음에 연산이 끝나면 배열을 모두 통합해서 하나로 만들어준다.
import * as R from 'ramda'
const callAndAppend = R.pipe(
R.ap([R.multiply(2),R.add(10)]),
R.tap(a => console.log(a))
)
const input = [1,2,3]
const result = callAndAppend(input)
실행결과
[2,4,6,11,12,13]
위 코드가 그 예시이다.
처음에 2를 곱해준값을 가지고 그다음에 원본 배열에 10을 더한 값을 가지는것을 볼 수 있다.