Правильный ответ: «Это действительно не имеет значения».В некоторых ранее опубликованных ответах говорится, что второй подход - O (n + m), но я позволю себе не согласиться.Точно такие же «m» операции также будут выполняться при первом подходе.В худшем случае, даже если вы рассматриваете вторую партию операций как «m» (что на самом деле не имеет особого смысла - мы говорим о тех же n элементах, которые приведены в качестве входных данных - это не так, как работает анализ сложности), вв худшем случае m == n, а сложность будет O (2n), что в конечном итоге равно O (n).
Чтобы ответить на ваш вопрос, да, второй подход будет повторяться посбор дважды, в то время как первый сделает это только один раз.Но это, вероятно, не будет иметь никакого значения для вас.В подобных случаях вы, вероятно, захотите улучшить читабельность по сравнению с эффективностью.Сколько предметов у вашей коллекции?10?100?Лучше написать код, который будет легче поддерживать с течением времени, чем стремиться к максимальной эффективности все время - потому что большую часть времени он просто не имеет никакого значения.
Более того, повторение более одного раза нене означает, что ваш код работает медленнее.Это все о том, что внутри каждой петли.Например:
for (const item of arr) {
// do A
// do B
}
Фактически совпадает с:
for (const item of arr) {
// do A
}
for (const item of arr) {
// do B
}
Сам цикл for не увеличивает нагрузку на процессор.Хотя в любом случае вы, возможно, захотите написать один цикл, если читаемость кода улучшится, когда вы делаете два цикла, продолжайте и сделайте это.
Эффективность заключается в выборе правильного алгоритма
Если вам действительно нужно быть эффективным, вы не хотите перебирать всю коллекцию, даже один раз.Вам нужен более умный способ сделать это: либо разделяй и властвуй (O (log n)), либо используй хеш-карты (O (1)).Хэш-карта в день устраняет неэффективность: -)
Делайте вещи только один раз
Теперь вернемся к вашему примеру, если я обнаружу, что повторяюсь снова и снова и делаю то же самоекаждый раз я просто запускаю операцию фильтрации в начале:
// during initialization
const things = [];
const notThings = [];
for (const item of arr) {
item.thing ? things.push(item) : notThings.push(item);
}
// now every time you need to iterate through the items...
for (const a of notThings) { // replaced arr with notThings
// if (a.thing) // <- no need to check this anymore
// continue;
// do a thing
}
И затем вы можете свободно перебирать notThings
, зная, что ненужные элементы уже отфильтрованы.Имеет смысл?
Критика "for of
быстрее вызова методов"
Некоторые люди любят утверждать, что for of
всегда будет быстрее, чем вызов forEach()
.Мы просто не можем этого сказать.Существует множество интерпретаторов Javascript, и для каждой из них существуют разные версии, каждая из которых имеет свои способы оптимизации.Чтобы доказать свою точку зрения, я смог заставить filter() + forEach()
работать быстрее, чем for of
в Node.js v10 на MacOS Mojave:
const COLLECTION_SIZE = 10000;
const RUNS = 10000;
const collection = Array.from(Array(COLLECTION_SIZE), (e, i) => i);
function forOf() {
for (const item of collection) {
if (item % 2 === 0) {
continue;
}
// do something
}
}
function filterForEach() {
collection
.filter(item => item % 2 === 0)
.forEach(item => { /* do something */ });
}
const fns = [forOf, filterForEach];
function timed(fn) {
if (!fn.times) fn.times = [];
const i = fn.times.length;
fn.times[i] = process.hrtime.bigint();
fn();
fn.times[i] = process.hrtime.bigint() - fn.times[i];
}
for (let r = 0; r < RUNS; r++) {
for (const fn of fns) {
timed(fn);
}
}
for (const fn of fns) {
const times = fn.times;
times.sort((a, b) => a - b);
const median = times[Math.floor(times.length / 2)];
const name = fn.constructor.name;
console.info(`${name}: ${median}`);
}
Раз (в наносекундах):
forOf: 81704
filterForEach: 32709
for of
был постоянно медленнее во всех тестах, которые я выполнял, всегда примерно на 50% медленнее.В этом суть этого ответа: не доверяйте деталям реализации каждого интерпретатора, потому что они могут (и будут) меняться со временем.Если вы не разрабатываете для встраиваемых систем или систем с высокой эффективностью / малой задержкой - где вам нужно быть как можно ближе к аппаратному обеспечению - сначала ознакомьтесь со сложностями алгоритма.