ramdajs 주요 함수
June 27, 2018 - [functional, ramdajs]
흔히 사용될 수 있는 ramdajs 함수들을 알아본다
R.append
배열의 끝에 특정 요소를 추가한다
R.append("tests", ["write", "more"]) //=> ['write', 'more', 'tests']
vs vanillaJS
const arr = ["write", "more"]
arr.push("tests")
console.log(arr) // ['write', 'more', 'tests']
R.prepend
배열의 처음에 특정 요소를 추가
R.prepend("fee", ["fi", "fo", "fum"]) //=> ['fee', 'fi', 'fo', 'fum']
vs vanillaJS
const arr = ["fi", "fo", "fum"]
arr.unshift("fee")
console.log(arr) // ["fee", "fi", "fo", "fum"]
R.insert
배열의 특정 위치에 요소를 삽입
R.insert(2, "x", [1, 2, 3, 4]) //=> [1,2,'x',3,4]
vs vanillaJS
const arr = [1, 2, 3, 4]
arr.splice(2, 0, "x")
console.log(arr) // [1,2,'x',3,4]
R.pipe
순서대로 연결된 함수를 리턴
var f = R.pipe(Math.pow, R.negate, R.inc)
f(3, 4) // -(3^4) + 1
R.compose
역순으로 연결된 함수를 리턴
R.compose(Math.abs, R.add(1), R.multiply(2))(-4)
// => 7 cause) | (-4 * 2) + 1 |
R.flip
첫번째 두번째 인자의 위치 순서를 뒤집어 놓은 함수를 리턴. (전체 인자의 순서를 뒤집는 것은 아님)
var mergeThree = (a, b, c) => [].concat(a, b, c)
mergeThree(1, 2, 3) //=> [1, 2, 3]
R.flip(mergeThree)(1, 2, 3) //=> [2, 1, 3]
R.forEach
배열의 각 요소를 인자로 전달받는 특정 함수를 실행시키고 인자로 전달받았던 배열을 리턴한다
- Array.prototype.forEach 는 undefined 를 리턴
- 처리함수가 두번째 인자로 index 를 전달받지 못한다
var printXPlusFive = x => console.log(x + 5)
R.forEach(printXPlusFive, [1, 2, 3]) //=> [1, 2, 3]
// logs 6
// logs 7
// logs 8
vs vanillaJS
var printXPlusFive = x => console.log(x + 5);
[1,2,3].forEach(printXPlusFive);
R.map
리스트의 각 요소를 다른 값으로 매핑한다. Array.prototype.map 와 유사.
주의) 매핑함수의 2번째 인자로 index가 전달되지 않는다
var double = x => x * 2
R.map(double, [1, 2, 3]) //=> [2, 4, 6]
R.map(double, { x: 1, y: 2, z: 3 }) //=> {x: 2, y: 4, z: 6}
R.filter
배열의 특정 요소들만 필터링. Array.prototype.filter 와 유사
var isEven = n => n % 2 === 0
R.filter(isEven, [1, 2, 3, 4]) //=> [2, 4]
R.filter(isEven, { a: 1, b: 2, c: 3, d: 4 }) //=> {b: 2, d: 4}
R.reduce
리스트의 각 요소를 순회하며 특정 값으로 축약한다/ Array.prototype.reduce 와 유사
R.reduce(R.subtract, 0, [1, 2, 3, 4]) // => ((((0 - 1) - 2) - 3) - 4) = -10
// - -10
// / \ / \
// - 4 -6 4
// / \ / \
// - 3 ==> -3 3
// / \ / \
// - 2 -1 2
// / \ / \
// 0 1 0 1
vanillaJS
;[1, 2, 3, 4].reduce((a, c) => a - c, 0) // => ((((0 - 1) - 2) - 3) - 4) = -10
R.prop
객체의 특정 속성의 값을 리턴한다
R.prop("x", { x: 100 }) //=> 100
R.prop("x", {}) //=> undefined
R.props
여러개의 속성의 값을 배열로 리턴
R.props(["x", "y"], { x: 1, y: 2 }) //=> [1, 2]
R.props(["c", "a", "b"], { b: 2, a: 1 }) //=> [undefined, 1, 2]
var fullName = R.compose(R.join(" "), R.props(["first", "last"]))
fullName({ last: "Bullet-Tooth", age: 33, first: "Tony" }) //=> 'Tony Bullet-Tooth'
R.find
배열에서 특정 조건을 만족하는 첫번재 요소를 리턴. Array.prototype.find 와 유사
var xs = [{ a: 1 }, { a: 2 }, { a: 3 }]
R.find(R.propEq("a", 2))(xs) //=> {a: 2}
R.find(R.propEq("a", 4))(xs) //=> undefined
vanillaJS
var xs = [{ a: 1 }, { a: 2 }, { a: 3 }]
xs.find(o => o.a === 2) //=> {a: 2}
xs.find(o => o.a === 4) //=> undefined
R.findIndex
배열에서 특정 조건을 만족하는 첫번째 요소의 인덱스를 리턴. Array.prototype.findIndex 와 유사
var xs = [{a: 1}, {a: 2}, {a: 3}];
R.findIndex(R.propEq('a', 2))(xs); //=> 1
R.findIndex(R.propEq('a', 4))(xs); //=> -1
R.propEq
속성의 값이 특정 값과 일치하는지 여부를 리턴
var abby = { name: "Abby", age: 7, hair: "blond" }
var fred = { name: "Fred", age: 12, hair: "brown" }
var rusty = { name: "Rusty", age: 10, hair: "brown" }
var alois = { name: "Alois", age: 15, disposition: "surly" }
var kids = [abby, fred, rusty, alois]
var hasBrownHair = R.propEq("hair", "brown")
R.filter(hasBrownHair, kids) //=> [fred, rusty]
R.propIs
속성의 값의 타입이 특정 타입과 일치하는지 여부를 리턴
R.propIs(Number, "x", { x: 1, y: 2 }) //=> true
R.propIs(Number, "x", { x: "foo" }) //=> false
R.propIs(Number, "x", {}) //=> false
R.range
특정 범위의 연속적인 자연수 배열을 리턴
R.range(1, 5) //=> [1, 2, 3, 4]
R.range(50, 53) //=> [50, 51, 52]
R.add
두 수의 합을 리턴
R.range(1, 5) //=> [1, 2, 3, 4]
R.range(50, 53) //=> [50, 51, 52]
R.and
두 값의 && 연산 결과를 리턴
R.and(true, true) //=> true
R.and(true, false) //=> false
R.and(false, true) //=> false
R.and(false, false) //=> false
R.or
두 값의 || 연산 결과를 리턴
R.or(true, true) //=> true
R.or(true, false) //=> true
R.or(false, true) //=> true
R.or(false, false) //=> false
R.partial
왼쪽부터 인자가 부분적용된 함수를 리턴
var multiply2 = (a, b) => a * b
var double = R.partial(multiply2, [2])
double(2) //=> 4
var greet = (salutation, title, firstName, lastName) =>
salutation + ", " + title + " " + firstName + " " + lastName + "!"
var sayHello = R.partial(greet, ["Hello"])
var sayHelloToMs = R.partial(sayHello, ["Ms."])
sayHelloToMs("Jane", "Jones") //=> 'Hello, Ms. Jane Jones!'
R.partialRight
오른쪽부터 인자가 부분적용된 함수를 리턴
var greet = (salutation, title, firstName, lastName) =>
salutation + ", " + title + " " + firstName + " " + lastName + "!"
var greetMsJaneJones = R.partialRight(greet, ["Ms.", "Jane", "Jones"])
greetMsJaneJones("Hello") //=> 'Hello, Ms. Jane Jones!'
R.partition
특정 기준으로 리스트를 둘로 나눔
R.partition(R.contains("s"), ["sss", "ttt", "foo", "bars"])
// => [ [ 'sss', 'bars' ], [ 'ttt', 'foo' ] ]
R.partition(R.contains("s"), { a: "sss", b: "ttt", foo: "bars" })
// => [ { a: 'sss', foo: 'bars' }, { b: 'ttt' } ]
R.equals
두 값을 비교, 순환참조 객체도 비교 가능
R.equals(1, 1) //=> true
R.equals(1, "1") //=> false
R.equals([1, 2, 3], [1, 2, 3]) //=> true
var a = {}
a.v = a
var b = {}
b.v = b
R.equals(a, b) //=> true
R.contains
리스트에 특정 요소가 포함되는지 여부를 리턴. 내부적으로 R.equals 를 이용해 비교
R.contains(3, [1, 2, 3]) //=> true
R.contains(4, [1, 2, 3]) //=> false
R.contains({ name: "Fred" }, [{ name: "Fred" }]) //=> true
R.contains([42], [[42]]) //=> true
R.any
리스트에서 특정 조건을 만족하는 요소가 있는지 여부를 리턴
var lessThan0 = R.flip(R.lt)(0)
var lessThan2 = R.flip(R.lt)(2)
R.any(lessThan0)([1, 2]) //=> false
R.any(lessThan2)([1, 2]) //=> true
R.tail
머리 빼고 리턴
R.tail([1, 2, 3]) //=> [2, 3]
R.tail([1, 2]) //=> [2]
R.tail([1]) //=> []
R.tail([]) //=> []
R.tail("abc") //=> 'bc'
R.tail("ab") //=> 'b'
R.tail("a") //=> ''
R.tail("") //=> ''
R.init
배열의 마지막 요소만 뺀 앞 부분 전부 리턴
R.init([1, 2, 3]) //=> [1, 2]
R.init([1, 2]) //=> [1]
R.init([1]) //=> []
R.init([]) //=> []
R.init("abc") //=> 'ab'
R.init("ab") //=> 'a'
R.init("a") //=> ''
R.init("") //=> ''
R.split
문자열을 특정 기준으로 나눔, String.prototype.split 과 유사
var pathComponents = R.split("/")
R.tail(pathComponents("/usr/local/bin/node")) //=> ['usr', 'local', 'bin', 'node']
R.split(".", "a.b.c.xyz.d") //=> ['a', 'b', 'c', 'xyz', 'd']
R.clone
깊은복사
var objects = [{}, {}, {}]
var objectsClone = R.clone(objects)
objects === objectsClone //=> false
objects[0] === objectsClone[0] //=> false
R.isNil
undefined
or null
체크
R.isNil(null) //=> true
R.isNil(undefined) //=> true
R.isNil(0) //=> false
R.isNil([]) //=> false
R.complement
true
or false
를 리턴하는 함수를 인자로 받아서 그 반대 결과를 리턴하는 함수를 만든다
var isNotNil = R.complement(R.isNil)
isNil(null) //=> true
isNotNil(null) //=> false
isNil(7) //=> false
isNotNil(7) //=> true
R.concat
두 배열을 병합
R.concat("ABC", "DEF") // 'ABCDEF'
R.concat([4, 5, 6], [1, 2, 3]) //=> [4, 5, 6, 1, 2, 3]
R.concat([], []) //=> []
R.T
항상 true
리턴
R.T() //=> true
R.F
항상 false
리턴
R.F() //=> false
R.always
항상 주어진 값을 리턴
var t = R.always("Tee")
t() //=> 'Tee'
R.cond
true를 만날 때까지 조건을 체크, true를 만나면 해당 함수를 실행, true를 못 만나면 undefined 리턴. switch
문과 비슷
var fn = R.cond([
[R.equals(0), R.always("water freezes at 0°C")],
[R.equals(100), R.always("water boils at 100°C")],
[R.T, temp => "nothing special happens at " + temp + "°C"],
])
fn(0) //=> 'water freezes at 0°C'
fn(50) //=> 'nothing special happens at 50°C'
fn(100) //=> 'water boils at 100°C'
R.ifElse
if else 구문과 비슷
var incCount = R.ifElse(
R.has("count"),
R.over(R.lensProp("count"), R.inc),
R.assoc("count", 1)
)
incCount({}) //=> { count: 1 }
incCount({ count: 1 }) //=> { count: 2 }
R.sort
조건에 따라 배열을 정렬
var diff = function (a, b) {
return a - b
}
R.sort(diff, [4, 2, 7, 5]) //=> [2, 4, 5, 7]
R.flatten
이상한? 배열을 받아서 1차원 배열로 리턴
R.flatten([1, 2, [3, 4], 5, [6, [7, 8, [9, [10, 11], 12]]]])
//=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
R.keys
모든 속성을 배열로 리턴, Object.keys
와 유사
R.keys({ a: 1, b: 2, c: 3 }) //=> ['a', 'b', 'c']
R.values
모든 값을 배열로 리턴, Object.values
와 유사
R.values({ a: 1, b: 2, c: 3 }) //=> [1, 2, 3]
R.trim
문자열 양끝의 공백제거
R.trim(" xyz ") //=> 'xyz'
vanillaJS
" xyz ".trim()
R.all
모든 요소가 어떤 조건을 만족하는 지 체크
var equals3 = R.equals(3)
R.all(equals3)([3, 3, 3, 3]) //=> true
R.all(equals3)([3, 3, 1, 3]) //=> false
R.curry
원하는 순서대로 인자 하나씩 부분적용 가능, R.__
를 이용해 해당인자 잠시 비워두기도 가능. R.__
는 R.curry
를 통한 함수에서만 사용이 가능
var g = R.curry((a, b, c) => a - b - c)
// 아래 예시는 모두 동일한 결과
g(1, 2, 3)
g(1)(2)(3)
g(1, 2)(3)
g(1)(2, 3)
// 2번째 인자 먼저 적용하고 싶으면
g(R.__, 2)(1)(3)
// 3번째 인자 먼저 적용하려면
g(R.__, R.__, 3)(1)(2)
R.drop
앞쪽부터 n개의 요소를 제거한다
R.drop(1, ["foo", "bar", "baz"]) //=> ['bar', 'baz']
R.drop(2, ["foo", "bar", "baz"]) //=> ['baz']
R.drop(3, ["foo", "bar", "baz"]) //=> []
R.drop(4, ["foo", "bar", "baz"]) //=> []
R.drop(3, "ramda") //=> 'da'
R.dropLast
뒤쪽부터 n개의 요소를 제거한다
R.dropLast(1, ["foo", "bar", "baz"]) //=> ['foo', 'bar']
R.dropLast(2, ["foo", "bar", "baz"]) //=> ['foo']
R.dropLast(3, ["foo", "bar", "baz"]) //=> []
R.dropLast(4, ["foo", "bar", "baz"]) //=> []
R.dropLast(3, "ramda") //=> 'ra'