最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to find first n array items that match a condition without looping through entire array - Stack Overflow

programmeradmin2浏览0评论

I am trying to find the first 100 items in a very large array that match a condition and I'd prefer to end the loop once I've found those 100 for efficiency sake, since the method for matching the items is expensive.

The problem is that doing:

const results = largeArray.filter(item => checkItemValidity(item)).slice(0, 100);

will find all the results in the large array before returning the first 100, which is too wasteful for me.

And doing this:

const results = largeArray.slice(0, 100).filter(item => checkItemValidity(item));

could return less than 100 results.

Please what's the most efficient way of doing this?

I am trying to find the first 100 items in a very large array that match a condition and I'd prefer to end the loop once I've found those 100 for efficiency sake, since the method for matching the items is expensive.

The problem is that doing:

const results = largeArray.filter(item => checkItemValidity(item)).slice(0, 100);

will find all the results in the large array before returning the first 100, which is too wasteful for me.

And doing this:

const results = largeArray.slice(0, 100).filter(item => checkItemValidity(item));

could return less than 100 results.

Please what's the most efficient way of doing this?

Share Improve this question asked Aug 8, 2020 at 16:18 JayCodistJayCodist 2,5443 gold badges14 silver badges34 bronze badges 4
  • Why not use break in a loop? – Aditya Prasoon Commented Aug 8, 2020 at 16:21
  • 8 Use a for loop and break when you have enough results – charlietfl Commented Aug 8, 2020 at 16:21
  • You could add a counter to your javascript. Every time it finds an item fitting your conditions, add +1 to the counter. Then once the counter reaches 100, stop the loop. – kvncnls Commented Aug 8, 2020 at 16:21
  • Not an exact duplicate but the general idea is to break from array methods: Short circuit Array.forEach like calling break – adiga Commented Aug 8, 2020 at 16:26
Add a comment  | 

8 Answers 8

Reset to default 8

Rather than putting a conditional and break inside a for loop, just add the extra length check in the for condition itself

const data = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14"],
      isValid = n => !(n%2),
      res = [],
      max = 5;

for (let i = 0; i < data.length && res.length < max; i++) {
   isValid(data[i]) && res.push(data[i]);
}

console.log(res)

There are several array methods that will exit early Array.some, Array.every, Array.find, Array.findIndex

You can use them to stop the iteration when you need.

Example using Array.find

const data = [-1,-6,-6,-6,1,-2,2,3,4,-5,5,6,7,-8,8,9,-10,10,11,-1,2,3,4,5,-6,7,8,-9,10,11,];
const first10 = [];

data.find(item => (item > 0 && first10.push(item), first10.length >= 10));

console.log(first10 +"");

You ocul take a generator function and exit of the wanted length is found.

function* getFirst(array, fn, n) {
    let i = 0;
    while (i < array.length) {
        if (fn(array[i])) {
            yield array[i];
            if (!--n) return;
        }
        i++;
    }
}
const
    expFn = x => x % 2 === 0,
    array = [2, 4, 5, 1, 3, 7, 9, 10, 6, 0];
    
console.log(...getFirst(array, expFn, 4));

The most efficient way would be to use a for construct instead of a function and then break out when you have reached your limit.

const results = []
for (const item of largeArray) {
  // End the loop
  if(results.length === 100) break

  // Add items to the results
  checkItemValidity(item) && results.push(item)
} 

console.log(results)

You can use something like this. I.e. Finding the first 5 odd numbers

var data = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14"]

var filterData = [];
for (let i = 0; i < data.length; i++) {
  if (data[i] % 2 === 0) {
    filterData.push(data[i]);
  }
  // Track count  console.log(i)
  if (filterData.length === 5)
    break;
}

console.log(filterData)

You would need to do a standard "for" loop as filter function returns a new array of the given array so here is how I would approach this:

let largeArray = ["foo", "bar", "foo", "bar"]
let validateArray = ["foo"]
let newArray = []
for (let item of largeArray){
    //change number to how many items needed
    if (newArray.length === 2){
       console.log(newArray)
       // Output would be ["foo", "foo"]
       break;
    }
    // If you have a custom function to return true or false replace here
    if (validateArray.includes(item)){
        newArray.push(item);
    }
}

If you are not returning strings you might need to create a custom function to return true or false depending on how you would define a validate data

I'll recommend you use findIndex, the problem with the some and every is that if the array is empty it will return true

Reference: Why does Array.prototype.every return true on an empty array?

I'm going to assume that what is expensive is the function that you are using to filter items in the array, not the actual iteration.

In that case, I would recommend using the array objects .reduce() method. Inside the function you pass to it, you can check whether your accumulator is already large enough. If it isn't, then you can conditionally add to it.

const results = largeArray.reduce(( accumulator , item )=> {
  if (accumulator.length <= 100) {
    if (checkItemValidity(item)) {
      accumulator.push(item)
    }
  }
  return accumulator
}, [])

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论