배열과 객체 다루기

2017년 03월 17일


배열 다루기 1

함수형 프로그래밍은 불변 값에 대한 프로그래밍입니다.

배열에도 마찬가지입니다. 함수형 프로그래밍으로 배열을 다루면 기존의 어떤 배열도 수정되지 않습니다.

range

R.range는 일정한 구간의 값을 생성합니다. 별로 특별할 것은 없지만 유용하게 사용할 수 있습니다.

Ramda에서 제공하는 함수이기 때문에 커링을 이용할 수 있다는 특징이 있습니다.

import * as R from 'ramda';

R.range(10, 42); // [10, 11, 12, ..., 40, 41]
const fromZeroTo = R.range(0);
fromZeroTo(4); // [0, 1, 2, 3]

repeat

R.repeat는 특정한 값을 반복하는 배열을 생성합니다. 마찬가지로 커링을 이용할 수 있습니다.

import * as R from 'ramda';

R.repeat('Hello', 3); // ['Hello', 'Hello', 'Hello']
const repeater = R.repeat('WOW');
repeater(3); // ['WOW', 'WOW', 'WOW']

concat

Array.concat과 비슷하게 동작합니다. 두 개의 배열을 인자로 받아 하나로 합친 새로운 배열을 생성합니다.

import * as R from 'ramda';

R.concat(['A', 'B'], ['C', 'D']);  // ['A', 'B', 'C', 'D']

zip

zip은 두 개의 배열을 받아 순서쌍의 배열을 만듭니다. 길이가 다르다면 짧은 쪽에 맞춰 동작합니다.

import * as R from 'ramda';

const xs = ['A', 'B'];
const ys = R.range(0, 5);
R.zip(xs, ys); // [['A', 0], ['B', 1]]

append, prepend

이 두 함수는 배열에 새로운 원소룰 추가합니다. append는 배열의 뒷쪽에, prepend는 앞쪽에 추가합니다

import * as R from 'ramda';

R.append('D', ['A', 'B', 'C']);  // ['A', 'B', 'C', 'D']
R.prepend('A', ['B', 'C', 'D']); // ['A', 'B', 'C', 'D']

다음은 data의 모든 원소 배열의 앞에 A를, 뒤에 Z를 추가하는 예시입니다. 함수를 커링하고 조합해서 새로운 함수를 파생시킵니다.

import * as R from 'ramda';

const data = [
  ['B', 'C', 'D', 'E', 'F', 'G'],
  ['C', 'F', 'J', 'Q', 'V', 'Y'],
  ['G', 'H', 'O', 'S', 'U', 'X']
];

const f = R.pipe(R.prepend('A'), R.append('Z'));

const a = data.map(f);
const b = data.map(R.prepend('A')).map(R.append('Z'));

const z = [
  ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'Z'],
  ['A', 'C', 'F', 'J', 'Q', 'V', 'Y', 'Z'],
  ['A', 'G', 'H', 'O', 'S', 'U', 'X', 'Z']
];

R.equals(z, a); // true
R.equals(z, b); // true
R.equals(a, b); // true

take, drop

take는 배열의 앞부분에서 일부를 추출, drop은 일부를 제거하는 함수입니다. 비슷한 함수로 추출할 원소의 갯수가 아닌 조건을 받는 takeWhile과 dropWhile도 있습니다.

import * as R from 'ramda';

const xs = R.range(0, 10); 
R.take(5, xs); // [0, 1, 2, 3, 4];
R.drop(5, xs); // [5, 6, 7, 8, 9];

const isFive = R.equals(5);
R.takeWhile(isFive, xs); // [0, 1, 2, 3, 4];
R.dropWhile(isFive, xs); // [5, 6, 7, 8, 9];

any, all

Array.some과 Array.every에 해당하는 함수입니다. 배열의 원소가 특정한 조건을 만족하는지 검사할 수 있습니다.

R.any는 조건을 만족하는 원소가 하나라도 있는지, R.all은 모든 원소가 조건을 만족하는지 검사합니다.

import * as R from 'ramda';

const xs = R.range(0, 5);
R.any((x) => x > 3, xs); // true
R.all((x) => x > 3, xs); // false