简体   繁体   English

更有效的数组搜索

[英]More efficient array search

I'd like to pull a particular object from an array of objects based on a unique property of that object (ie, a key). 我想根据对象的唯一属性(即键)从对象数组中提取特定对象。

In the following, I'm searching for an element in 'arr' where the key is 8. 在下面的代码中,我正在'arr'中搜索键为8的元素。

var myElement = arr.filter(function(element) {
  return element.key === 8;
});

This works, but every time this runs, it will iterate through all elements in the array, even after the correct element has been found. 这是可行的,但是每次运行时,即使找到了正确的元素,它也会遍历数组中的所有元素。 For example, if it finds myElement at index 4, but there are 100 elements in the array, the snippet is running 25x more than it needs to. 例如,如果它在索引4处找到myElement,但是数组中有100个元素,则该片段的运行量将比需要的多25倍。

Is there a more efficient way, or a way to terminate filter() when it has found myElement? 有没有更有效的方法,还是找到myElement时终止filter()的方法?

I feel like I've missed something obvious... 我觉得我错过了一些明显的事情...

You actually want a find function that returns when the first occurrence is found. 实际上,您实际上需要一个find函数,该函数在find第一个匹配项时返回。 You can use Array.prototype.find if you are on ECMAScript 6 spec or you can implement a simple find like: 如果您使用的是ECMAScript 6规范,则可以使用Array.prototype.find ,也可以实现一个简单的find例如:

function find8(arr) {
    // type checks skipped for brevity
    var i = 0,
        j = arr.length;

    for (; i < j; i++) {
        if (arr[i].key === 8) {
            return arr[i];
        }
    }

    throw new Error('Not found');
}

If you want a more generic solution that accepts predicates (ie functions that return a boolean value), you can write a more generic function like: 如果您想要一个更通用的接受谓词的解决方案(即返回布尔值的functions ),则可以编写一个更通用的函数,例如:

function find(arr, predicate) {
    // Again, type checks skipped for brevity
    var i = 0,
        j = arr.length;

    for (; i < j; i++) {
        // Note the condition is now a call to the predicate function
        if (predicate(arr[i])) {
            return arr[i];
        }
    }

    throw new Error('Not found');
}
for (var i=0; i<arr.length; i++) {
    if (arr[i].key === 8) {
        console.log('FOUND ITEM AT KEY '+8);
        break;
    }
}

It sounds like you'd be better off with something like this: 听起来您最好像这样:

function findByKey(items, key) {
    for (var index = 0; index < items.length; index++) {
        var item = items[index];
        if (item.key === key) {
            return item;
        }
    }
    return null;
}

Note that if your list is sorted, you can improve upon that by doing a binary-search instead. 请注意,如果您的列表已排序,则可以通过执行二进制搜索来改进此列表。 Though personally I'd suggest hashing (assuming that the same key isn't used twice). 虽然我个人建议哈希(假设相同的密钥不使用两次)。 Something like: 就像是:

var array = [/* your data here... */];
var map = {};

//do this once; or once each time your array changes
for (var index = 0; index < array.length; index++) {
    var item = array[index];
    map[item.key] = item;
}

//now find things by doing this
var itemWithKey8 = map[8];

I'd handle this with a simple for loop (used a function for generic re-use): 我将通过一个简单的for循环(用于泛型重用的函数)来处理此问题:

function findObject(arr, cond)
    for (i = 0; i < arr.length; i++) {
        if (cond(arr[i]){
            return arr[i];
        }
    }
}

// now call fincObject(myArray, function(element){element.key === 8})

Or, if you know you are going to do this many times, create a mapping which should be a lot faster: 或者,如果你知道你要做很多次,创造应该是快了很多的映射:

function makeMapping(arr, keyFunc){
    var mapping = {};
    for (var i = 0; i < arr.length; i++) {
        mapping[keyFunc(arr[i])] = arr[i];
    }
    return mapping;
}

This returns an object mapping 8 to the object with key.id === 8 . 这将返回一个将8映射到key.id === 8的对象的对象。 Your keyFunc would be: 您的keyFunc将是:

function keyFunc(element){
    return element.key;
}

Why reinvent the wheel? 为什么要重新发明轮子? There are a lot of similar answers here, so I'll share a different approach--by far my favorite approach. 这里有很多类似的答案,所以我将分享一种不同的方法-到目前为止是我最喜欢的方法。 There is an excellent library called linq.js (both standalone and jQuery plugin versions) which makes searching, filtering, sorting, etc. a breeze. 有一个很棒的库叫做linq.js (独立版本和jQuery插件版本),使搜索,过滤,排序等工作变得轻而易举。

var myElement = Enumerable.From(arr).FirstOrDefault(null,         function(element) {
      return element.key === 8;
});

In the above example, the first element that matches the conditions is returned. 在上面的示例中,返回了符合条件的第一个元素。 If nothing is found, null is returned (the first parameter is the default value to return). 如果未找到任何内容,则返回null(第一个参数是要返回的默认值)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM