From 81195dc2e067079a4e776e68806061bf350ccfc0 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 24 Jun 2026 19:28:29 +0000 Subject: [PATCH] I have optimized the common item name lookups by replacing the search command inside the loop. --- .jules/bolt.md | 3 +++ R/aFIPC.R | 48 ++++++++++++------------------------------------ 2 files changed, 15 insertions(+), 36 deletions(-) create mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..75a4a32 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2025-02-23 - Avoid `grep` in inner loops for exact string matching on column names in R +**Learning:** In the core `autoFIPC` logic, there were multiple inner loops that utilized `length(grep(paste0('^', name, '$'), colnames)) == 1` to perform exact string matching of items over columns. This regex-based lookup inside tight loops leads to severe performance degradation as the number of common items or columns increases. Furthermore, computing `levels(as.factor(vector))` inside a loop is substantially slower than utilizing `unique(vector)` for checking column categories. +**Action:** When evaluating exact matching against arrays of strings in R, extract the string lists outside the loop and use vectorized equality operators (`sum(extractedNames == targetName) == 1`) or `%in%`. Always replace `levels(as.factor())` with `unique()` for counting categorical values to prevent unnecessary conversion and sort overhead. diff --git a/R/aFIPC.R b/R/aFIPC.R index b6a9e6c..4710dff 100644 --- a/R/aFIPC.R +++ b/R/aFIPC.R @@ -546,20 +546,13 @@ autoFIPC <- 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)) { if ( - (length(grep( - paste0('^', newformCommonItemNames[i], '$'), - colnames(newformXDataK[colnames(newFormModel@Data$data)]) - )) == - 1) == - TRUE && - (length(grep( - paste0('^', oldformCommonItemNames[i], '$'), - colnames(oldformYDataK[colnames(oldFormModel@Data$data)]) - )) == - 1) == - TRUE + sum(newFormColNames == newformCommonItemNames[i]) == 1 && + sum(oldFormColNames == oldformCommonItemNames[i]) == 1 ) { IPDItemCount <- IPDItemCount + 1 IPDItemNamesOldForm[IPDItemCount] <- @@ -698,32 +691,15 @@ autoFIPC <- } } + newFormColNames <- colnames(newformXDataK[colnames(newFormModel@Data$data)]) + oldFormColNames <- colnames(oldformYDataK[colnames(oldFormModel@Data$data)]) + for (i in 1:length(oldformCommonItemNames)) { if ( - (length(grep( - paste0('^', newformCommonItemNames[i], '$'), - colnames(newformXDataK[colnames(newFormModel@Data$data)]) - )) == - 1) == - TRUE && - (length(grep( - paste0('^', oldformCommonItemNames[i], '$'), - colnames(oldformYDataK[colnames(oldFormModel@Data$data)]) - )) == - 1) == - TRUE && - (length(levels(as.factor( - newFormModel@Data$data[, grep( - paste0('^', newformCommonItemNames[i], '$'), - colnames(newformXDataK[colnames(newFormModel@Data$data)]) - )] - ))) == - length(levels(as.factor( - oldFormModel@Data$data[, grep( - paste0('^', oldformCommonItemNames[i], '$'), - colnames(oldformYDataK[colnames(oldFormModel@Data$data)]) - )] - )))) + sum(newFormColNames == newformCommonItemNames[i]) == 1 && + sum(oldFormColNames == oldformCommonItemNames[i]) == 1 && + length(na.omit(unique(newFormModel@Data$data[, newFormColNames == newformCommonItemNames[i]]))) == + length(na.omit(unique(oldFormModel@Data$data[, oldFormColNames == oldformCommonItemNames[i]]))) ) { message( 'applying ',