diff --git a/.jules/bolt.md b/.jules/bolt.md index 1c38f9c..2e7794b 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -7,3 +7,6 @@ ## 2024-07-08 - R 언어에서 루프 내 인덱스 검색(which) O(N) 병목 최적화 **Learning:** R에서 반복문 내부에서 특정 조건을 만족하는 데이터의 위치를 찾기 위해 `which()`를 여러 번 호출하면 매번 O(N)의 선형 탐색(linear scan)이 발생하여 데이터 크기가 클수록 성능이 크게 저하됩니다. 또한 `paste0()`를 이용한 불필요한 배열 단위 문자열 생성은 반복문 오버헤드를 가중시킵니다. **Action:** 조건에 맞는 인덱스를 최초 한 번 `split(seq_len(nrow(df)), df$column)`를 통해 리스트 형태로 캐싱(dictionary lookup)하여 루프 외부에서 O(1) 검색 체계로 만들고, 스칼라 값에 대한 불필요한 `paste0()` 함수 호출을 최적화(`paste(..., collapse=' ')`)하여 오버헤드를 줄입니다. +## 2026-07-11 - R 언어에서 루프 내 벡터 동적 확장 및 조건부 탐색 최적화 +**Learning:** R에서 for 루프 내에 동적으로 벡터 크기를 늘리면서 (`vector[i] <- value`) 조건을 검사하는 것은 O(N^2)의 복사 오버헤드(copy-on-modify)를 발생시키며 매 반복마다 `match()` 스캔을 수행하면 성능 저하를 초래합니다. +**Action:** 루프 외부에 벡터화된 `match()`를 한 번만 수행하여 유효한 인덱스를 찾고, 벡터 인덱싱(`vector[idx]`)으로 한 번에 데이터를 추출하여 불필요한 루프 오버헤드 및 동적 메모리 재할당을 방지하여 O(1) 수준으로 성능을 개선해야 합니다. diff --git a/R/aFIPC.R b/R/aFIPC.R index 22552f8..87cd3b4 100644 --- a/R/aFIPC.R +++ b/R/aFIPC.R @@ -619,25 +619,19 @@ autoFIPC <- rep('newForm', nrow(newformXDataK)) )) IPDItemCount <- 0 - IPDItemNamesOldForm <- vector() - IPDItemNamesNewForm <- vector() # IPD target item checking newFormColNames <- colnames(newformXDataK[colnames(newFormModel@Data$data)]) oldFormColNames <- colnames(oldformYDataK[colnames(oldFormModel@Data$data)]) - for (i in 1:length(oldformCommonItemNames)) { - newFormItemName <- newFormColNames[match(newformCommonItemNames[i], newFormColNames)] - oldFormItemName <- oldFormColNames[match(oldformCommonItemNames[i], oldFormColNames)] - if ( - !is.na(newFormItemName) && - !is.na(oldFormItemName) - ) { - IPDItemCount <- IPDItemCount + 1 - IPDItemNamesOldForm[IPDItemCount] <- oldFormItemName - IPDItemNamesNewForm[IPDItemCount] <- newFormItemName - } - } + # ⚡ Bolt: Vectorized match() to avoid dynamic array growth overhead inside a for loop + idxNew <- match(newformCommonItemNames, newFormColNames) + idxOld <- match(oldformCommonItemNames, oldFormColNames) + valid_idx <- !is.na(idxNew) & !is.na(idxOld) + + IPDItemNamesNewForm <- newFormColNames[idxNew[valid_idx]] + IPDItemNamesOldForm <- oldFormColNames[idxOld[valid_idx]] + IPDItemCount <- length(IPDItemNamesNewForm) # IPD Data generation IPDItemList <-