Reputation: 5553
Just saw someone write this:
let id = 1;
...
let employee = null;
for (const e of employees) {
if (e.id === id) {
employee = e;
break;
}
}
seems like an overcomplicated way of writing this:
let id = 1;
...
let employee = employees.find(e => e.id === id);
Is there any benefit to using a loop with a break
vs a find()
?
What is find()
's implementation behind the curtain?
Upvotes: 11
Views: 20233
Reputation: 56
If you know, with some degree of certainty, that the element you seek is closer to the end (right side) of the array, using for() loop instead of find could be beneficial. You would construct your for() loop to start in reverse, hence it will travel only the length from the end to the element. E.g.looking for 99 in [1..100]. The for() will only compare 2 elements, whereas find will compare 99 elements.
Elaboration on Performance. I found it odd that everything I read so far was stating that find() is faster than for() [in forward search], because when I ran it few times I observed the opposite, i.e. find() was about 30%-50% slower. Like this:
So I ran it 1 million times, then I averaged the performance time. To clarify the premise:
I created an array of 100,000 elements. Each elements is an object with 2 elements, with key = number from 0 to 100,000, and the array was sorted by the key. From this array I attempted to find the object with key=97900, which is towards the end.
let arr = [{key: 1, value: 1},...]
Results (average time in ms) a) Find: 0.078452628 ms b) For: 0.217990078 ms c) For [reversed]: 0.000223515 ms
From the plot we can see that for() has more unpredictable outliers. We can also observe that at the beginning find() has slower performance.
If you want to run tests by yourself, here is some starter code:
let arr = [];
for (let i = 0; i < 100000; i++) {
arr.push({
key: i,
value: i ^ 2
});
}
console.log("find() vs for() vs reverse for() 97,900 in 100,000, array of objects")
console.time("find")
arr.find(i => {
return i.key === 97900
})
let find = console.timeEnd("find")
console.time("for")
for (let i = 0; i < arr.length; i++) {
if (arr[i].key === 97900) {
break
}
}
console.timeEnd("for")
console.time("for-rev")
for (let i = arr.lenght - 1; i > 0; i--) {
if (arr[i].key === 97900) {
break
}
}
console.timeEnd("for-rev")
Upvotes: 0
Reputation: 20844
I implemented both approaches as two methods with the same signature (forBreakMethod(x)
and findMethod (x)
) and passed them through a simple performance test spec.
(() => {
const test = (DATA_LENGTH = 1000, INDEX = 9, TESTS_COUNT = 10000) => {
// data initialization
const employees = [];
for (let i = 1; i <= DATA_LENGTH; i++){
employees.push({ id: i });
}
// methods initialization
const forBreakMethod = (x) => {
const length = employees.length;
for (let i = 0; i < length; i++) {
if (x === employees.id) {
return employees[i];
}
}
}
const findMethod = (x) => {
return employees.find(item => x === item.id);
}
// for-break test
const time1 = performance.now();
for (let i = 0; i < TESTS_COUNT; i++) {
forBreakMethod(INDEX);
}
const time2 = performance.now();
console.log(`[for-break] find ${INDEX} from ${DATA_LENGTH}: ${time2 - time1}`);
// find test
const time3 = performance.now();
for (let i = 0; i < TESTS_COUNT; i++) {
findMethod(INDEX);
}
const time4 = performance.now();
console.log(`[Array.find] find ${INDEX} from ${DATA_LENGTH}: ${time4 - time3}`);
console.log('---------------');
};
test(10, 1, 1000000);
test(10, 5, 1000000);
test(10, 9, 1000000);
console.log('\n');
test(100, 10, 100000);
test(100, 50, 100000);
test(100, 99, 100000);
console.log('\n');
test(1000, 10, 10000);
test(1000, 500, 10000);
test(1000, 999, 10000);
console.log('\n');
test(10000, 10, 10000);
test(10000, 5000, 10000);
test(10000, 9999, 10000);
})();
A conclusion I see is that the Array.find approach has an advantage if the item we want to find lives in the left part of the data array, but its performance getting low when the result index goes to the right. The for-break approach seems more stable, since its performance does not depend on the index we want to find, but its cost is significant.
So very rough, I would say that the Array.find approach could be considered as more performant if we are going to walk through the first half of the data array, otherwise I would use the for-break approach.
PS Chrome, Safari, Firefox, 2018.
Upvotes: 3
Reputation: 1869
It is fairly obvious that the native find()
function is faster than a loop algorithm. But the OP asked "Is there any benefit to using a loop...?"
A theoretical reason someone might want to loop is if they needed to process non-matching elements along the way.
Upvotes: 2
Reputation: 1368
Tried this:
var startTime, endTime;
function start() {
startTime = new Date();
};
function end() {
endTime = new Date();
var timeDiff = endTime - startTime; //in ms
console.log(timeDiff + " milliseconds");
}
let employees = [];
for (var i = 10000; i > 0; i--){
let thisEmployee = {
id: i,
name: "Person" + i
}
employees.push(thisEmployee);
}
let id = 1;
let employee1 = null;
start();
for (const e of employees) {
if (e.id === id) {
employee1 = e;
break;
}
}
end();
console.log("Method1: ", JSON.stringify(employee1));
start();
let employee2 = employees.find(e => e.id === id);
end();
console.log("Method2: ", JSON.stringify(employee2));
First method is much slower:
"12 milliseconds"
"Method1: "
"{\"id\":1,\"name\":\"Person1\"}"
"0 milliseconds"
"Method2: "
"{\"id\":1,\"name\":\"Person1\"}"
Upvotes: 4
Reputation: 7933
.find()
is faster than for...break
.
Check this link for test results. for...break
is 30% slower than .find()
.find()
source code can be found here
.find()
is not supported in older browsers like IE11 and below. You need to use a polyfill instead.
.find()
is better due to complexity level and the internal algorithm used. Using for...break
you will always doing a linear search which means n * n
repetitions. The bigger the array, the slower the function.
Upvotes: 15
Reputation: 1580
So I just tried this:
const array = [0, 1, 2, 3, 4, 5,];
for (const i of array) {
console.log(i);
if (i === 3)
break;
}
array.find(i => {
console.log(i);
return i === 3;
});
Both of them output
0
1
2
3
So, they both short circuit on the first answer they find as I would expect, but as for specific performance I can't say for certain whether one is better than the other. I imagine the performance would be comparable if not identical.
The one big difference that stands out to me is that find
returns the value, but the for loop you have to handle the value in the loop, otherwise assign it to a variable to use later. A minor detail but it could potentially make find much more readable for someone else looking at your code.
Upvotes: 0