【问题标题】:Is there a fast way to select item from array of objects in Javascript?有没有一种快速的方法可以从 Javascript 中的对象数组中选择项目?
【发布时间】:2015-01-21 05:21:15
【问题描述】:

我有一个数组:

[
    {
        key: 'some key',
        value: 'some value'
    }, {
        ...
    }, ...
]

有没有什么简单的方法可以得到这个数组的某个元素,而无需遍历它并将每个实际键与所需的键进行比较?

我目前有一个函数

var select = function(what, from) {
    for (var i in from) {
        if (from[i].key == what) {
            return from[i];
        }
    }
    return null;
};

我相信有更好的方法来处理它。

【问题讨论】:

  • ".. 这个数组的某些元素没有遍历它..":不!不可能。

标签: javascript arrays node.js javascript-objects


【解决方案1】:

简短的回答是。有很多选项可以让你的代码更简洁——就像上面所有的一样——但你仍然需要一个一个地迭代它们。

你可以做两件事来让它变得更好:

转换为地图

如果您要进行一次或两次以上的搜索,则将其转换为键的映射,因此至少每次后续查找都是 O(1) 而不是 O(n)。许多答案表明 - 我在自己的代码中经常使用它 - 但这是一个基本版本(有一个简写 un underscore/lodash):

var i, hash = {};
for (i = 0; i < arr.length; i++) {
  hash[arr[i].key] = arr[i].value;
}

那么对于所有未来的查找来说,这很简单:

var value = hash[key];

搜索算法

如果出于某种原因它需要保留为数组,并且您对该数组的值有一定的了解,则可以使用各种搜索算法。一个一个地循环遍历它们有利于均匀分布,但仍然是 O(n),平均而言,每次需要循环遍历数组的一半 (n/2)。

但是搜索算法超出了这篇文章...

【讨论】:

    【解决方案2】:

    你很亲密。在这种特殊情况下,这将是最快的形式:

    var select = function(key, expected, from) {
        var i;
        for (i = 0; i < from.length; i += 1) {
            if (from[i][key] === expected) {
                return from[i];
            }
        }
        return null;
    };
    
    select('thing', 'foo', [{thing: 'foo'}]);
    // => {thing: 'foo'}
    

    但是您需要最大速度吗?或者更优雅的通用解决方案是否适合您?如果是这样,请使用谓词:

    var find = function (array, predicate) {
        var i;
        for (i = 0; i < array.length; i += 1) {
            if (predicate(array[i])) {
                return array[i];
            }
        }
        return null;
    };
    
    // Find, in an array, an item which passes the following truth test.
    find([{thing: 'foo'}], function (item) {
        return item.thing === 'foo';
    });
    // => {thing: 'foo'}
    

    如果您不喜欢编写这样的样板实用程序代码,我建议您使用 lodash 之类的库。 It has a find method already,它比我们想出的任何东西都更快、更强大。

    【讨论】:

      【解决方案3】:

      不幸的是,如果你改变你的结构来使用属性,它会更快。任何其他方法都需要对数组进行迭代,因此总是比下面的效率低。

      var keyValueObj = {
        someKey: 'someValue',
        nextKey: 'nextValue'
      }
      
      // represents 'someValue'
      keyValueObj['someKey']
      

      【讨论】:

        【解决方案4】:

        如果您使用的是现代浏览器,这应该会很神奇:

        function include(arr,obj) {
            return (arr.indexOf(obj) != -1);
        }
        

        或在 jquery 中

        $.inArray(value, array)
        

        针对您的评论,请查看此link,这也将解决您在评论中的问题。

        【讨论】:

        • 我不确定我是否了解如何使用它。例如,[1, 2, 3].indexOf(1) 返回0,而[{a: 1}, {a: 2}].indexOf({a: 1}) 返回-1。我应该如何使用indexOf 在数组中查找非原始索引?
        【解决方案5】:

        如果您的键是字符串,则将它们用作对象属性而不是对象数组

        如果您的键是对象,请使用Map()

        【讨论】:

          【解决方案6】:

          您可以将您的数组重构为一个地图,按照设计,这有助于快速有效地查找:

          {
              'some key': {
                  value: 'some value'
              },
              'some other key': {
                  value: 'some other value'
              },
          }
          

          那么您的select 函数将尽可能短

          var select = function(what, from) {
              return from[what];
          };
          

          如果您希望select() 的返回值仍然具有.key 属性(这是多余的,因为调用者已经知道它为what),通过保留key 很容易实现地图元素中的属性,或在返回之前自动添加到select()

          【讨论】:

            【解决方案7】:

            如果你需要经常运行这个函数,我建议你创建一个索引:

            var yourItemList = [{...}],
                select = (function (items) {
                    var i = 0,
                        l = items.length,
                        preparedItems = {};
            
                    for (; i < l; ++i) {
                        preparedItems[items[i].key] = items[i].value;
                    }
            
                    return function (key) {
                        return preparedItems[key];
                    };
                }(yourItemList));
            

            这样你只在项目列表上迭代一次。之后每个select('theKeyYouNeed') 只使用映射的“索引”。

            【讨论】:

              【解决方案8】:

              你可以filter数组。它内置于 Array 方法中,因此您无需声明其他辅助函数

              var arr = [
                  {
                      key: 'some key',
                      value: 'some value'
                  }, {
                      key: 'some key1',
                      value: 'some value'
                  }
              ];
              
              arr = arr.filter(function(item) {
                  return item.key === 'some key'
              });
              

              现在arr 只有第一个对象(因为它的键等于“某个键”)。您找到的对象是arr[0]

              当您只需要一个对象时,您可以使用find() 而不是filter()。请注意,find() 是 ES6 的一部分,不支持所有主流浏览器

              【讨论】:

              • DV 没有保证。问题是关于检索项目。该项目是一个数组元素还是内容都没有关系。 +1。
              猜你喜欢
              • 1970-01-01
              • 2016-03-11
              • 1970-01-01
              • 1970-01-01
              • 2021-10-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-09-05
              相关资源
              最近更新 更多