제목이 모든 것을 말해줍니다 🐐. 제가 가장 좋아하는 자바스크립트 배열 메서드: Array.reduce()에 대해 이야기해보려고 합니다. 많은 경쟁자들이 있지만, 제 말을 들어보세요. reduce()는 단순한 메서드가 아닙니다. 그것은 일종의 생활 방식이에요✨.
처음에 reduce를 발견했을 때는 좀 겁먹었지만, 사용법을 확실히 익히고 나니 완전히 게임 체인저였습니다. 갑자기 배열에서 복잡한 연산을 쉽게 수행할 수 있게 되었고, 제 코드가 더 빠르고 깔끔해졌습니다.
하지만 제 말만 믿지 마세요. reduce()로 무엇을 할 수 있는지 몇 가지 예를 보여드릴게요. 이제 Array.reduce()의 매력에 빠져봅시다! 🐐
reduce()의 가장 간단한 사용 사례 중 하나는 여러 숫자를 합산하는 것입니다. 예를 들어, 정수 배열이 있고 총합을 구하고 싶다고 가정해봅시다.
const numbers: number[] = [1, 2, 3, 4, 5];
const sum: number = numbers.reduce((acc, curr) => acc + curr, 0);
console.log(sum); // Output: 15
짜잔! 한 줄의 코드로 배열의 모든 요소의 합을 계산했습니다. 누산기(Accumulator)의 초기 값은 0으로 설정하고, 각 반복에서 현재 요소를 누산기에 더합니다.
배열 안에 배열이 있어서 이를 하나의 배열로 평탄화하고 싶었던 적이 있나요?
const nestedArray: number[][] = [[1, 2], [3, 4], [5, 6]];
const flattenedArray: number[] = nestedArray.reduce((acc, curr) => acc.concat(curr), []);
console.log(flattenedArray); // Output: [1, 2, 3, 4, 5, 6]
이 예에서 우리는 빈 배열을 초기 누산기 값으로 시작합니다. 그런 다음 각 반복 concat() 메서드를 사용하여 현재 하위 배열을 누산기에 연결합니다. 결과는 완벽하게 평탄화된 배열입니다.
Array.flat()
을 사용할 수도 있지만, 각 항목에 대해 추가 작업을 수행해야 할 경우를 대비해 reduce를 사용하는 방법을 아는 것이 중요합니다.
특정 속성을 기준으로 객체 배열을 그룹화해야 한다고 가정해봅시다. reduce()가 이 작업에 완벽한 도구입니다.
tsx코드 복사
interface Person {
name: string;
age: number;
}
const people: Person[] = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Charlie', age: 25 },
{ name: 'Dave', age: 30 }
];
const groupedByAge: { [key: number]: Person[] } = people.reduce((acc, curr) => {
if (!acc[curr.age]) {
acc[curr.age] = [];
}
acc[curr.age].push(curr);
return acc;
}, {});
console.log(groupedByAge);
/*
Output:
{
'25': [{ name: 'Alice', age: 25 }, { name: 'Charlie', age: 25 }],
'30': [{ name: 'Bob', age: 30 }, { name: 'Dave', age: 30 }]
}
*/
이 경우, 객체를 초기 누산기 값으로 사용합니다. 누산기에 현재 나이에 대한 속성이 이미 있는지 확인합니다. 없다면 해당 나이에 대한 빈 배열을 만듭니다. 그런 다음 현재 객체를 해당 나이 배열에 추가합니다. 결과적으로 나이를 키로 하고, 값을 그 나이의 사람들로 이루어진 배열로 가지는 객체를 얻습니다.
이제 새로운 groupBy
메서드도 사용할 수 있지만, 이 고전적인 방법을 이해하는 것이 중요합니다.
개인적으로 가장 좋아하는 것은 reduce()를 사용하여 배열에서 조회 맵을 생성하는 것입니다. 성능과 코드 가독성 면에서 게임 체인저입니다. 느린 find() 또는 filter() 호출을 그만 사용하세요.
interface Product {
id: number;
name: string;
price: number;
}
const products: Product[] = [
{ id: 1, name: 'Laptop', price: 999 },
{ id: 2, name: 'Phone', price: 699 },
{ id: 3, name: 'Tablet', price: 499 },
];
const productMap: { [key: number]: Product } = products.reduce((acc, curr) => {
acc[curr.id] = curr;
return acc;
}, {});
console.log(productMap);
/*
Output:
{
'1': { id: 1, name: 'Laptop', price: 999 },
'2': { id: 2, name: 'Phone', price: 699 },
'3': { id: 3, name: 'Tablet', price: 499 }
}
*/
// ID로 제품 접근하기
const laptop: Product = productMap[1];
console.log(laptop); // Output: { id: 1, name: 'Laptop', price: 999 }
reduce()를 사용하여 조회 맵을 생성하면 고유 식별자로 요소를 상수 시간 복잡도로 접근할 수 있습니다. 특정 항목을 찾기 위해 배열을 반복할 필요가 없습니다.
배열에서 요소의 발생 횟수를 세야 했던 적이 있나요? reduce()가 도와줄 수 있습니다.
const fruits: string[] = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
const fruitCounts: { [key: string]: number } = fruits.reduce((acc, curr) => {
acc[curr] = (acc[curr] || 0) + 1;
return acc;
}, {});
console.log(fruitCounts);
/*
Output:
{
'apple': 3,
'banana': 2,
'orange': 1
}
*/
이 예에서 우리는 빈 객체를 초기 누산기 값으로 설정합니다. 각 과일에 대해 누산기 객체에 해당 과일이 속성으로 존재하는지 확인합니다. 존재하면 그 값을 1 증가시키고, 그렇지 않으면 1로 초기화합니다. 결과는 배열에서 각 과일이 몇 번 나타나는지 알려주는 객체입니다.
함수형 프로그래밍 애호가들은 이 예를 좋아할 것입니다. reduce()는 함수를 조합하는 데 강력한 도구입니다. 데이터를 단계별로 변환하는 함수 파이프라인을 만들 수 있습니다.
const add5 = (x: number): number => x + 5;
const multiply3 = (x: number): number => x * 3;
const subtract2 = (x: number): number => x - 2;
const composedFunctions: ((x: number) => number)[] = [add5, multiply3, subtract2];
const result: number = composedFunctions.reduce((acc, curr) => curr(acc), 10);
console.log(result); // Output: 43
이 예에서 우리는 순서대로 적용하고 싶은 함수 배열이 있고, 초기 값 10을 설정합니다. reduce()를 사용하여 각 함수를 반복하고, 각 함수의 결과를 다음 함수에 입력으로 전달합니다. 최종 결과는 모든 함수를 조합한 결과입니다.
Redux를 사용해본 적이 있다면, 애플리케이션 상태 관리를 얼마나 강력하게 할 수 있는지 알 것입니다. 놀랍게도 reduce()를 사용하여 간단한 Redux 스타일 상태 관리 시스템을 구현할 수 있습니다.
interface State {
count: number;
todos: string[];
}
interface Action {
type: string;
payload?: any;
}
const initialState: State = {
count: 0,
todos: [],
};
const actions: Action[] = [
{ type: 'INCREMENT_COUNT' },
{ type: 'ADD_TODO', payload: 'Learn Array.reduce()' },
{ type: 'INCREMENT_COUNT' },
{ type: 'ADD_TODO', payload: 'Master TypeScript' },
];
const reducer = (state: State, action: Action): State => {
switch (action.type) {
case 'INCREMENT_COUNT':
return { ...state, count: state.count + 1 };
case 'ADD_TODO':
return { ...state, todos: [...state.todos, action.payload] };
default:
return state;
}
};
const finalState: State = actions.reduce(reducer, initialState);
console.log(finalState);
/*
Output:
{
count: 2,
todos: ['Learn Array.reduce()', 'Master TypeScript']
}
이 예에서 우리는 초기 상태 객체와 액션 배열이 있습니다. 현재 상태와 액션을 받아들이고, 액션 유형에 따라 새로운 상태를 반환하는 리듀서 함수를 정의합니다. reduce()를 사용하여 각 액션을 순차적으로 상태에 적용하여 최종 상태를 얻습니다. 작은 Redux와도 같습니다.
때때로 중복 값이 있는 배열에서 고유한 값만 추출해야 할 때가 있습니다. reduce()가 쉽게 도와줍니다.
const numbers: number[] = [1, 2, 3, 2, 4, 3, 5, 1, 6];
const uniqueNumbers: number[] = numbers.reduce((acc, curr) => {
if (!acc.includes(curr)) {
acc.push(curr);
}
return acc;
}, []);
console.log(uniqueNumbers); // Output: [1, 2, 3, 4, 5, 6]
여기서 우리는 빈 배열을 초기 누산기 값으로 설정합니다. 원래 배열의 각 숫자에 대해, includes() 메서드를 사용하여 누산기에 이미 존재하는지 확인합니다. 존재하지 않으면 누산기 배열에 추가합니다. 최종 결과는 원래 배열에서 고유 값만 포함된 배열입니다.
숫자 집합의 평균을 계산하고 싶으신가요? reduce()가 도와줄 수 있습니다!
const grades: number[] = [85, 90, 92, 88, 95];
const average: number = grades.reduce((acc, curr, index, array) => {
acc += curr;
if (index === array.length - 1) {
return acc / array.length;
}
return acc;
}, 0);
console.log(average); // Output: 90
이 예에서 우리는 초기 누산기를 0으로 설정합니다. 각 성적을 반복하여 누산기에 더합니다. 마지막 요소에 도달하면, 누산기를 총 성적 수로 나누어 평균을 계산합니다.
Array.reduce()는 매우 강력하고 다재다능하지만, 특히 대규모 배열이나 복잡한 연산을 다룰 때 성능 문제를 염두에 두어야 합니다. 하나의 일반적인 함정은 reduce()의 각 반복에서 새로운 객체나 배열을 생성하는 것입니다. 이는 과도한 메모리 할당을 유발하고 성능에 영향을 미칠 수 있습니다.
예를 들어, 다음 코드를 고려해보세요:
const numbers: number[] = [1, 2, 3, 4, 5];
const doubledNumbers: number[] = numbers.reduce((acc, curr) => {
return [...acc, curr * 2];
}, []);
console.log(doubledNumbers); // Output: [2, 4, 6, 8, 10]
이 경우, 우리는 스프레드 연산자(...)를 사용하여 각 반복에서 새로운 배열을 생성합니다. 이는 비효율적일 수 있습니다. 대신, 누산기 배열을 직접 변경하여 코드를 최적화할 수 있습니다:
const numbers: number[] = [1, 2, 3, 4, 5];
const doubledNumbers: number[] = numbers.reduce((acc, curr) => {
acc.push(curr * 2);
return acc;
}, []);
console.log(doubledNumbers); // Output: [2, 4, 6, 8, 10]
push()를 사용하여 누산기 배열을 변경함으로써, 각 반복에서 새로운 배열을 생성하는 것을 피하고 성능을 향상시킵니다.
유사하게, 객체를 다룰 때도 스프레드 연산자 대신 누산기 객체를 직접 변경하는 것이 더 효율적입니다:
const people: Person[] = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Charlie', age: 25 },
{ name: 'Dave', age: 30 }
];
const groupedByAge: { [key: number]: Person[] } = people.reduce((acc, curr) => {
if (!acc[curr.age]) {
acc[curr.age] = [];
}
acc[curr.age].push(curr);
return acc;
}, {});
누산기 객체를 직접 변경함으로써 reduce() 연산의 성능을 최적화할 수 있습니다.
그러나, 어떤 경우에는 각 반복에서 새로운 객체나 배열을 생성하는 것이 필요하거나 더 읽기 쉬울 수 있습니다. 특정 사용 사례와 데이터 크기에 따라 성능과 코드 명확성 사이의 균형을 맞추는 것이 중요합니다.
이상입니다. Array.reduce()의 힘과 다재다능함을 보여주는 9가지 놀라운 사용 사례를 소개했습니다. 숫자 합산부터 배열 평탄화, 객체 그룹화, 조회 맵 생성, 발생 횟수 세기, 함수 조합, 상태 관리 구현, 고유 값 생성, 평균 계산까지, Array.reduce()
는 여러분의 자바스크립트 도구 상자에서 강력한 도구임을 입증합니다.
어떻게 생각하시나요? 여러분이 가장 좋아하는 배열 메서드는 무엇이고, 왜 그렇게 생각하시나요?
읽어주셔서 감사합니다. reduce()의 힘이 여러분과 함께하기를 바랍니다. ✨🐐✨
마지막으로 하나만 더 말하자면 😁
애자일 개발 팀에서 일하신다면, 제 무료 플래닝 포커 및 회고 앱 Kollabe를 확인해보세요.