다음은 레시피 등록에서 재료를 추가하는 기능입니다.
selectBox에서 값을 선택할 때 마다 재료에 해당하는 단위가 바뀌고, 상태배열 selects에 선택한 값을 추가합니다.
기존 코드
const upDateIngredient = (e, index) => {
const ingredientId = e.target.value;
const ingredientName = e.target.options[e.target.selectedIndex].textContent;
let ingredientUnit = "";
// 기존 상태배열에 중복 데이터가 존재하는지 검사
for(let i = 0; i < selects.length; i++){
if(ingredientId === selects[i].ingredientId){
setSelects(selects.filter((select) => select.index !== index)); //삭제
alert('이미 존재하는 재료입니다.');
return;
}
}
//선택한 재료의 단위 설정
for (let i = 0; i < ingredients.length; i++) {
if (ingredientId === String(ingredients[i].ingredientId)) {
ingredientUnit = ingredients[i].ingredientUnit;
break; // 원하는 값을 찾으면 루프를 중단
}
}
//선택한 재료 상태 배열에 추가
setSelects(prevSelects =>
prevSelects.map( select =>
select.index === index ? {
...select,
ingredientId:ingredientId,
ingredientName:ingredientName,
ingredientUnit:ingredientUnit
} :
select
)
);
}
[문제]
두 번의 for 루프를 사용하여 selects와 ingredients 배열을 탐색하고 있다. 배열 탐색이 많은 경우 시간이 오래 걸릴 수 있음
[해결방법]
중복 확인을 위한 Set 사용:
- selects 배열에서 이미 선택된 ingredientId를 확인할 때, 배열 탐색 대신 Set을 사용하여 O(1) 복잡도로 중복 여부를 확인
재료 단위 탐색을 위한 Map 사용:
- ingredients 배열을 미리 Map으로 변환하여 재료 ID로 단위를 O(1) 시간 복잡도로 조회 가능
이 방법을 통해 반복적인 배열 탐색을 제거하고, 성능을 최적화 할 수 있습니다.
변경된 코드
// selects 배열의 중복 확인을 위해 Set으로 변환
const selectedIds = new Set(selects.map(select => select.ingredientId));
if (selectedIds.has(ingredientId)) {
setSelects(selects.filter((select) => select.index !== index)); //삭제
alert('이미 존재하는 재료입니다.');
return;
}
// ingredients 배열을 Map으로 변환해 탐색 최적화
const ingredientMap = new Map(ingredients.map(ingredient => [String(ingredient.ingredientId), ingredient.ingredientUnit]));
// Map에서 단위를 바로 찾아서 할당
ingredientUnit = ingredientMap.get(ingredientId) || "";
최적화 전 성능
- 중복 확인 (selects 배열 탐색)
- selects 배열을 for 루프로 순차 탐색하면서 중복 확인
- 시간 복잡도는 O(n) (여기서 n은 selects 배열의 길이)
- 재료 단위 설정 (ingredients 배열 탐색)
- ingredients 배열을 for 루프로 탐색해 ingredientId와 일치하는 항목을 찾음
- 시간 복잡도는 O(m) (여기서 m은 ingredients 배열의 길이)
따라서 전체 시간 복잡도는 O(n) + O(m), 즉 selects와 ingredients의 배열 크기에 비례해 성능이 저하됩니다.
최적화 후 성능 분석
- 중복 확인 (Set 사용)
- Set을 사용해 중복 확인을 O(1) 복잡도로 줄였습니다. Set.has() 메서드는 상수 시간 안에 요소가 있는지 확인할 수 있습니다.
- 재료 단위 설정 (Map 사용)
- Map을 사용해 재료의 단위를 조회하는 작업도 O(1) 복잡도로 줄였습니다. Map.get() 메서드도 상수 시간 안에 값에 접근할 수 있습니다.
최적화 후, 배열을 한 번 순회하여 Set과 Map을 생성하는 초기 비용은 여전히 O(n) + O(m)이지만, 실제 upDateIngredient 함수가 실행되는 순간에는 각 작업이 O(1) 복잡도로 실행됩니다.
성능 향상 비교
- 최적화 전: upDateIngredient 함수 실행마다 O(n) + O(m) 시간 소요
- 최적화 후: Set과 Map 생성에 O(n) + O(m) 시간이 걸리지만, 이후 중복 확인과 단위 조회는 O(1)
최적화된 코드에서는 배열 크기가 커질수록 (selects와 ingredients에 많은 항목이 있을 때) 성능 차이가 커집니다.
특히 selects나 ingredients 배열이 매우 크다면, 최적화 전에는 이벤트가 발생할 때마다 시간이 점점 더 많이 소요되겠지만, 최적화 후에는 이벤트 핸들러가 상수 시간 내에 실행되므로 성능이 크게 개선됩니다
결과적으로, 이 최적화는 대규모 데이터 셋을 다룰 때 성능 이득이 눈에 띄며, 특히 배열 크기가 클수록 성능 향상이 두드러지게됩니다.
'Language > Java Script' 카테고리의 다른 글
[JavaScript] Set : 중복 제거와 효율적인 데이터 관리 (4) | 2024.10.18 |
---|---|
[JavaScript] var, let, const 차이 (0) | 2023.08.29 |