【问题标题】:Better way to find object in array instead of looping?在数组中查找对象而不是循环的更好方法?
【发布时间】:2013-03-23 21:06:48
【问题描述】:

示例

链接:http://jsfiddle.net/ewBGt/

var test = [{
    "name": "John Doo"
}, {
    "name": "Foo Bar"
}]

var find = 'John Doo'

console.log(test.indexOf(find)) // output: -1
console.log(test[find]) // output: undefined

$.each(test, function(index, object) {
    if(test[index].name === find)
        console.log(test[index]) // problem: this way is slow
})

问题

在上面的示例中,我有一个包含对象的数组。我需要找到有name = 'John Doo'的对象

我的.each 循环正在工作,但这部分将执行 100 次,并且测试将包含更多对象。所以我认为这种方式会很慢。

indexOf() 不起作用,因为我无法在对象中搜索名称。

问题

如何在当前数组中搜索带有name = 'John Doo' 的对象?

【问题讨论】:

  • 使用for循环(不是for-in来提高性能,一旦找到匹配项就使用break
  • 除非您的数组按name 排序,或者您有其他数据结构(例如按名称键入的地图),否则除了彻底搜索之外,没有其他方法可以找到它。跨度>
  • 如果您说循环本身将执行 100 次,那么我猜还有其他优化方法,但需要更多信息。
  • @Bondye - 你能控制数据的结构吗?如果名称是唯一的,并且您可以将它们作为其他数据的键,那么就有可能大大简化它。

标签: javascript jquery arrays object


【解决方案1】:

也许你应该在 jQuery 中使用$.grep 功能:

var test = [{
    "name": "John Doo"
}, {
    "name": "Foo Bar"
}]

var find = 'John Doo'

var found = $.grep(test, function(obj){
    return obj['name'] == find;
});

console.log(found);

小提琴:http://jsfiddle.net/ewBGt/3/

【讨论】:

  • 这不会比循环更有效。我不知道你为什么接受它作为你的答案。
  • 不能提高性能。此函数“过滤”一个数组,返回另一个数组,而不是对象本身。这意味着它肯定会处理整个数组,当它找到搜索的元素时不会中断循环执行。
【解决方案2】:

在这种情况下,我有时会做“可搜索的地图对象”。如果数组本身是静态的,则可以转换为映射,其中数组值可以是键和映射值索引。我假设值在您的示例中是唯一的。

Lo-Dash (www.lodash.com) 已创建实用程序选择,以便轻松循环等。检查一下!

注意:但通常你真的不必担心循环有 100 个元素的槽数组。

【讨论】:

  • 例如Lo-Dash 的 _.indexOf() 可以被告知您的数组是否已经排序。然后它将在您的数组中使用二进制搜索(非常快)。
  • 不知道为什么这个答案被否决。这是一个很好的解决方案。
  • 如果您需要多次搜索同一个数组,这是一个快速的解决方案,但请注意,如果您处理大型数组,它可能会占用大量内存,因为您必须构建另一个内存中的对象。将数组转换为映射的时间成本始终为 O(n),而不仅仅是在最坏的情况下,如在老式 for 循环中。一旦转换,此解决方案会导致 O(1) 执行时间。如果只需要搜索一次,或者担心内存问题,最好使用 for 循环方法。
【解决方案3】:

jQuery $.grep(或其他过滤功能)不是最佳解决方案。

$.grep 函数将循环遍历数组的所有元素,即使在循环期间已找到搜索的对象。

来自 jQuery grep 文档:

$.grep() 方法根据需要从数组中删除项目,以便 所有剩余的项目都通过了提供的测试。测试是一个函数 传递一个数组项和数组中该项的索引。 只有当测试返回 true 时,项目才会在结果数组中。

如果你的数组没有排序,没有什么能比得上这个:

var getObjectByName = function(name, array) {

    // (!) Cache the array length in a variable
    for (var i = 0, len = test.length; i < len; i++) {

        if (test[i].name === name)
            return test[i]; // Return as soon as the object is found

    }

    return null; // The searched object was not found

}

【讨论】:

  • Ehy Bondye,不客气。我很好奇你所说的前增量比后增量快,但事实证明这仅适用于 gcc 编译器,即“用于为后增量生成次优代码和这就是当时使用预增量的原因。编译器已经走了很长一段路,程序员不再需要以奇怪的方式思考来超越编译器“。如今,它是一种传奇。不过很有趣:)
【解决方案4】:

您唯一能做的就是使用内置数组方法(如果可用)而不是自己进行循环 - filter 方法适用于此。

但我希望 sbeliv01 在他的回答中使用的 jQuery 等 JS 库已经在内部检查了这一点(如果这些数组方法本身不可用,并提供一个后备解决方案)——所以不要指望大幅提升性能。

【讨论】:

  • filter方法和$.grep()有同样的问题:它会循环所有的数组对象。
【解决方案5】:

如果你只是想知道值是否存在,你可以像这样使用lodash的includes函数:

var find = 'John Doo'

[{ "name": "John Doo" }, { "name": "Foo Bar" }].some(function (hash) {
    if (_.includes(hash, find)) return true;
});

文档:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-31
    • 1970-01-01
    • 1970-01-01
    • 2019-03-21
    • 1970-01-01
    • 2017-09-29
    • 1970-01-01
    • 2020-08-31
    相关资源
    最近更新 更多