[英]Reduce the complexity of matching the elements of two arrays
我編寫了一個代碼,從谷歌工作表中提取列標題(工作表中的第一行)並將它們與對象數組進行比較。 對象數組中的每個 object 都有 3 個屬性:“問題”、“答案”和“類別”。 該代碼將每列的 header 與數組中每個 object 的“問題”屬性進行比較。
如果它們相似,則應將列的索引添加為某個字典的鍵,並將其值設置為包含該問題的答案和類別的數組。 無需過多解釋我為什么要這樣做,但我簡要地構建了這個邏輯,以便能夠對申請人對某些問題的回答進行評分(因此將問題的索引與其正確答案及其類別相關聯)。 這是代碼:
for (i = 0; i<columnHeaders[0].length; i++){
for (j=0; j<questionsObjects.length; j++){
//Get the current question and convert it to lower case
question = questionsObjects[j].question.toString().toLowerCase();
//Get column header, remove any spaces and new lines from it, and convert it to lower case
columnHeader = columnHeaders[0][i].toString().toLowerCase();
if (isStringSimilar(columnHeader, question)){
//Link the column index to its corresponding question object
var catAndAnswer = [];
catAndAnswer.push (questionsObjects[j].category.toLowerCase());
catAndAnswer.push (questionsObjects[j].rightAnswer.toLowerCase());
columnsQuestionsDictionary[i] = catAndAnswer;
} else {
SpreadsheetApp.getActive().getSheetByName("log").appendRow(["no", columnHeader, question]);
}
}
}
代碼運行良好,我唯一的問題是復雜性,它非常高。 在某些情況下,此方法需要將近 6 分鍾才能執行(對於這種情況,我有大約 40 列和 7 個問題對象),以解耦嵌套循環。 我想將問題值(問題 object 數組中的所有對象)連接成 1 個單個字符串,其中我在每個問題之前加上它在對象數組中的索引。
例如:
var str = "";
for (j=0; j<questionsObjects.length; j++){
str = str + j + questionsObjects[j].question.toString.toLowerCase();
}
然后,我可以通過列標題進行另一個單獨的循環,將每個 header 提取到一個字符串中,然后使用正則表達式exec
方法匹配長問題字符串(str)中的 header,如果找到它,我將在 str 中獲取它的索引,然后從中減去 1 以知道它在對象數組中的索引。 然而,事實證明,匹配正則表達式的復雜度是 O(N),其中 N 是我們搜索的字符串的長度(本例中為 str),因為這將在 columns 循環內,我看到我們仍然得到一個高復雜度,可以 go 到 O(N^2)。
如何優化這些嵌套循環,使代碼以最有效的方式運行?
好的,所以我使用了Nina Schholz在評論中建議的方式,我移動了columnHeader = columnHeaders[0][i].toString().toLowerCase();
在外部循環中而不是在內部循環中,因為它只在外部循環中需要。
運行代碼所需的時間從 ~295 秒減少到 ~208 秒,這很好。
我還嘗試切換循環順序,將外部循環設為內部循環,將內部循環設為外部循環,並相應地更新 i 和 j 的用法。 我這樣做是因為始終建議使用較少迭代的外部循環和具有更多迭代的內部循環(根據此資源),在我的情況下,迭代問題 object 數組的循環總是期望有迭代次數<= 另一個循環。
這是因為如果我們要計算 2 個嵌套循環的復雜度,它將是 (ixj) + i,其中 i 和 j 分別表示外循環和內循環的迭代次數。 切換循環順序不會影響乘法部分(ixj),但會影響加法部分。 因此,外部迭代次數總是比內部迭代次數少。
這樣做之后,運行的最后時間變成了 ~202 秒。
當然,由於現在切換了循環,因此我將此行移至內部循環: columnHeader = columnHeaders[0][i].toString().toLowerCase();
,但同時我移動了這個question = questionsObjects[j].question.toString().toLowerCase();
在外循環下,因為它只需要在那里。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.