亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

JavaScript for 循環性能問題

JavaScript for 循環性能問題

森欄 2023-06-09 14:52:35
循環數據集合的最佳方法是什么。我面臨的問題是性能低下。請參閱示例代碼片段。以下兩種方法存在性能問題。interface Day {    date: number;    disabled: boolean;}// sample dataconst monthDays: Day[] = Array.from({ length: 30 }, (v: unknown, k: number) => ({ date: k + 1, disabled: false }));const disabledDates: number[] = Array.from({ length: 30 }, (v, k) => k + 1);//set disabled dates// method 1let counter = 0;for (let day of monthDays) {    day.disabled = disabledDates.some(d => d === day.date);    counter++;}console.log(counter) // logs 30// method 2counter = 0;for (let day of monthDays) {    for (let date of disabledDates) {        counter++;        if (day.date === date) {            day.disabled = true;            break;        }    }}console.log(counter); // logs 494在我工作的應用程序中,我需要對數組進行 3 到 4 次迭代。這會導致應用程序性能低下。任何人都可以建議什么是最好的循環方式。
查看完整描述

2 回答

?
慕桂英3389331

TA貢獻2036條經驗 獲得超8個贊

無需再次檢查每個元素,.some您可以將您的值傳播到 an 中Set并檢查set.has()其內部女巫是否更快


你的時間復雜度從下降O(n^2)到O(n)


// sample data

let monthDays = Array.from({ length: 10000 }, (v, k) => ({ date: k + 1, disabled: false }));

const disabledDates = Array.from({ length: 10000 }, (v, k) => k + 1);


//set disabled dates

// method 1


let start = performance.now()

for (let day of monthDays) {

    day.disabled = disabledDates.some(d => d === day.date);

}

console.log(performance.now() - start);


//reset

monthDays = Array.from({ length: 10000 }, (v, k) => ({ date: k + 1, disabled: false }));


start = performance.now();

let set = new Set([ ...disabledDates ]);

for (let day of monthDays) {

   if(set.has(day.date)) {

      day.disabled = true;

   }else {

      day.disabled = false;

   }

}


console.log(performance.now() - start);


查看完整回答
反對 回復 2023-06-09
?
慕尼黑5688855

TA貢獻1848條經驗 獲得超2個贊

方法 1 和方法 2 具有完全相同的性能特征,但是,您測量它們的方法存在缺陷。使用方法 2,您計算代碼進行的外部和內部迭代,而使用方法 1,您只計算外部迭代。但是,.some()仍然對數據進行迭代:


// sample data

const monthDays = Array.from({ length: 30 }, (v, k) => ({ date: k + 1, disabled: false }));

const disabledDates = Array.from({ length: 30 }, (v, k) => k + 1);


//set disabled dates

// method 1

let counter = 0;

for (let day of monthDays) {

? ? day.disabled = disabledDates.some(d => {

? ? ? counter++;

? ? ? return d === day.date

? ? });

? ? counter++;

}


console.log(counter) // logs 495


由于您有兩個嵌套迭代,這兩種方法都表現出O(n*m)時間復雜度,其中n是的長度monthDaysm是 的長度disabledDates。這基本上是 的接近值的二次復雜度n并且m實際上是 的二次復雜度n = m(如示例所示)。

糾正這個問題的方法是消除嵌套循環,只處理一次數據。這很容易通過首先預先計算一個包含所有對象的Set對象disabledDates來實現,這樣您就不必遍歷數組來檢查它們是否存在而不是使用Set#has.

// sample data

const monthDays = Array.from({ length: 30 }, (v, k) => ({ date: k + 1, disabled: false }));

const disabledDates = new Set(Array.from({ length: 30 }, (v, k) => k + 1));


for (const day of monthDays) {

? day.disabled = disabledDates.has(day.date);

}


console.log(monthDays);

一次轉換為一組的復雜度為O(m),然后每次循環時您只有一次O(n)迭代。

  • 如果您只能創建一次集合,則重復迭代monthDays不需要包含該操作。這樣操作的復雜度就變成了O(n)。

  • 如果您每次都需要在循環之前創建一個集合,那么復雜性將變得O(n+m)比二次和線性更好。

請注意,這假定這.has()是一個O(1)操作。這是一個合理的假設,可能在大多數情況下都是正確的。然而,從技術上講,這并不能保證——規范定義了集合操作的次線性復雜度,所以你可能O(log n)復雜度,這意味著迭代monthDays和查找disabledDates將是O(n * log m).?即便如此,使用集合可能是最簡單的優化路徑。如果性能仍然是一個問題,那么生成一個對象作為查找表可能會更好:

//this should be generated

const lookup: Record<number, true> = {

? ? 1: true,

? ? 2: true,

? ? 3: true,

? ? /*...*/?

}


/*...*/


//fetch from lookup or set `false` if not in the lookup

const disabled: boolean = lookup[day.date] ?? false;


查看完整回答
反對 回復 2023-06-09
  • 2 回答
  • 0 關注
  • 165 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號