【问题标题】:How can I get the index of an object by its property in JavaScript?如何通过 JavaScript 中的属性获取对象的索引?
【发布时间】:2011-11-02 20:43:59
【问题描述】:

例如,我有:

var Data = [
  { id_list: 1, name: 'Nick', token: '312312' },
  { id_list: 2, name: 'John', token: '123123' },
]

然后,例如,我想按name 对这个对象进行排序/反转。然后我想得到这样的东西:

var Data = [
  { id_list: 2, name: 'John', token: '123123' },
  { id_list: 1, name: 'Nick', token: '312312' },
]

现在我想知道属性为name='John' 的对象的索引,以获取属性令牌的值。

我该如何解决这个问题?

【问题讨论】:

  • 为什么要先对列表进行排序再搜索属性?
  • JavaScript 对象是{Key:Value},我为你修好了。
  • 如果您浏览答案,似乎有一些原生的Data 对象。它只是一个大写的变量名,这是违反约定的。如果其他人对此感到困扰,我将对问题和答案进行编辑以修复此命名。

标签: javascript arrays object


【解决方案1】:

我知道的唯一方法是遍历所有数组:

var index = -1;
for(var i=0; i<Data.length; i++)
  if(Data[i].name === "John") {
    index = i;
    break;
  }

或不区分大小写:

var index = -1;
for(var i=0; i<Data.length; i++)
  if(Data[i].name.toLowerCase() === "john") {
    index = i;
    break;
  }

结果变量index包含对象的索引,如果没有找到则为-1。

【讨论】:

    【解决方案2】:

    您可以使用 Array.sort 使用自定义函数作为参数来定义您的排序机制。

    在你的例子中,它会给出:

    var Data = [
        {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
    ]
    
    Data.sort(function(a, b){
        return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
    });
    
    alert("First name is : " + Data[0].name); // alerts 'John'
    alert("Second name is : " + Data[1].name); // alerts 'Nick'
    

    如果 a 应该在 b 之前,排序函数必须返回 -1,如果 a 应该在 b 之后,则返回 1,如果两者相等,则返回 0。您可以在排序函数中定义正确的逻辑来对数组进行排序。

    错过了您想知道索引的问题的最后一部分。正如其他人所说,您必须遍历数组才能找到它。

    【讨论】:

      【解决方案3】:

      只需遍历您的数组并找到位置:

      var i = 0;
      for(var item in Data) {
          if(Data[item].name == 'John')
              break;
          i++;
      }
      alert(i);
      

      【讨论】:

      • 这应该是if(Data[item].name == 'John'),我帮你修好了。
      • 这一刻。如果“未找到”变量 i 包含正索引。并且要测试“未找到”需要比较 i===Data.length
      • 第二个时刻是数组是否包含非索引器自定义属性。例如:var 数据[1,2,3,4,5]; Data["test"]=7897; 比较输出:for(var i in Data)alert(Data[i]); 和 for(var i=0; i
      • 但是没有显式循环就没有办法了吗?
      【解决方案4】:

      正如其他答案所暗示的,遍历数组可能是最好的方法。但我会把它放在它自己的函数中,让它更抽象一点:

      function findWithAttr(array, attr, value) {
          for(var i = 0; i < array.length; i += 1) {
              if(array[i][attr] === value) {
                  return i;
              }
          }
          return -1;
      }
      
      var Data = [
          {id_list: 2, name: 'John', token: '123123'},
          {id_list: 1, name: 'Nick', token: '312312'}
      ];
      

      有了这个,你不仅可以找到哪个包含'John',还可以找到哪个包含令牌'312312':

      findWithAttr(Data, 'name', 'John'); // returns 0
      findWithAttr(Data, 'token', '312312'); // returns 1
      findWithAttr(Data, 'id_list', '10'); // returns -1
      

      该函数在未找到时返回 -1,因此它遵循与 Array.prototype.indexOf() 相同的构造。

      【讨论】:

      • 添加了扩展此功能的答案,以涵盖比一个属性级别更深的搜索。感谢这个克里斯 - 真的很有帮助:D
      • 对于那些对此解决方案有疑问的人,请记住 === 等号不仅会检查值,还会检查数据类型。因此,如果实际值是字符串,比较日期、数字和空值可能会返回 false。如果数据类型对您不重要,您可以使用 == 等号。
      • 不要这样做。了解如何使用高阶函数,这是旧的做事方式。
      【解决方案5】:

      这可能有用:

      function showProps(obj, objName) {
        var result = "";
        for (var i in obj)
          result += objName + "." + i + " = " + obj[i] + "\n";
        return result;
      }
      

      我从 Working with objects 复制了这个。

      【讨论】:

        【解决方案6】:

        一种典型的方式

        (function(){
          if (!Array.prototype.indexOfPropertyValue){
               Array.prototype.indexOfPropertyValue = function(prop, value){
              for (var index = 0; index < this.length; index++){
                if (this[index][prop]){
                  if (this[index][prop] == value){
                    return index;
                  }
                }
               }
              return -1;
            }
          }
         })();
        
         // Usage:
         var Data = [
           {id_list:1, name:'Nick', token:'312312'}, {id_list:2, name:'John', token:'123123'}];
        
         Data.indexOfPropertyValue('name', 'John'); // Returns 1 (index of array);
         Data.indexOfPropertyValue('name', 'Invalid name') // Returns -1 (no result);
         var indexOfArray = Data.indexOfPropertyValue('name', 'John');
         Data[indexOfArray] // Returns the desired object.
        

        【讨论】:

        • 我不得不稍微改变一下以适应我的情况——我正在寻找值为 null 的属性的索引,而第五行导致它跳过了该索引。
        【解决方案7】:

        由于排序部分已经回答。我只是要提出另一种优雅的方法来获取数组中属性的 indexOf

        你的例子是:

        var Data = [
            {id_list:1, name:'Nick', token:'312312'},
            {id_list:2, name:'John', token:'123123'}
        ]
        

        你可以这样做:

        var index = Data.map(function(e) { return e.name; }).indexOf('Nick');
        

        var Data = [{
            id_list: 1,
            name: 'Nick',
            token: '312312'
          },
          {
            id_list: 2,
            name: 'John',
            token: '123123'
          }
        ]
        var index = Data.map(function(e) {
          return e.name;
        }).indexOf('Nick');
        console.log(index)

        Array.prototype.map 在Internet Explorer 7 或 Internet Explorer 8 上不可用。ES5 Compatibility

        这里是 ES6 和箭头语法,更简单:

        const index = Data.map(e => e.name).indexOf('Nick');
        

        【讨论】:

        • 完美!与上述方法相比,该方法的效率如何?
        • 无论如何我都必须迭代整个数组。第一种方法不需要。
        • 简单,但要考虑使用大型数据集时的性能
        • ES2015 是否给我们提供了一种通过字段名称动态搜索的方法,例如
        • 在 ES6 版本中执行 map 然后 indexOf 确实意味着它们将在数组上循环两次。相反,您应该使用我的答案中显示的 findIndex 方法
        【解决方案8】:

        除了German Attanasio Ruiz's answer,您可以使用Array.reduce() 代替Array.map() 来消除第二个循环;

        var Data = [
            { name: 'hypno7oad' }
        ]
        var indexOfTarget = Data.reduce(function (indexOfTarget, element, currentIndex) {
            return (element.name === 'hypno7oad') ? currentIndex : indexOfTarget;
        }, -1);
        

        【讨论】:

          【解决方案9】:

          使用一个小的解决方法:

          创建一个以名称为索引的新数组。之后,所有搜索都将使用索引。所以,只有一个循环。之后你就不需要遍历所有元素了!

          var Data = [
              {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
              ]
          var searchArr = []
          Data.forEach(function(one){
            searchArr[one.name]=one;
          })
          console.log(searchArr['Nick'])
          

          http://jsbin.com/xibala/1/edit

          活生生的例子。

          【讨论】:

          • 这意味着首先循环遍历所有内容...然后修改对象(除非您克隆它们,但这会产生更多开销)。然后你再次循环(至少部分)。
          【解决方案10】:

          我扩展了Chris Pickett's answer,因为在我的情况下,我需要搜索不止一个属性级别:

          function findWithAttr(array, attr, value) {
            if (attr.indexOf('.') >= 0) {
              var split = attr.split('.');
              var attr1 = split[0];
              var attr2 = split[1];
              for(var i = 0; i < array.length; i += 1) {
                if(array[i][attr1][attr2] === value) {
                  return i;
                }
              }
            } else {
              for(var i = 0; i < array.length; i += 1) {
                if(array[i][attr] === value) {
                  return i;
                }
              }
            };
          };
          

          您可以将“attr1.attr2”传递给函数。

          【讨论】:

            【解决方案11】:

            如果您可以使用 ES6,数组现在具有 findIndex 函数。这意味着您可以执行以下操作:

            const index = Data.findIndex(item => item.name === 'John');
            

            【讨论】:

            • 传递最直接和优雅的解决方案,我会说 findIndex 不是贪婪的 - 在我的情况下这是完美的 - 但用户要注意,如果你有重复值的对象(即name: John 的两个对象)这将只返回第一个匹配项
            • @GrayedFox 你不是说不贪心吗?贪婪意味着更多结果,findIndex 只返回第一个匹配项。
            • 对不起@Jos 但我认为你不太了解what a greedy search algorithm does。贪心算法只考虑它手头的信息,这在计算上是有效的,例如,当您只需要一个结果时搜索列表中的项目。 findIndex 方法很贪心,因为它只返回第一个匹配项。如果它不贪心,它会继续搜索。您正在考虑日常英语中使用的“贪婪”一词,但在编程的上下文中(即 SO),它与您的想法相反;)
            • 感谢@GrayedFox 的解释。我对贪婪的引用实际上也来自编程,但与正则表达式有关,其中贪婪比非贪婪占用更多的字符! :-)
            • 完美。正是我想要的。谢谢。
            【解决方案12】:

            使用这个:

            Data.indexOf(_.find(Data, function(element) {
              return element.name === 'John';
            }));
            

            假设您使用的是Lodash 或Underscore.js。

            【讨论】:

              【解决方案13】:
              var fields = {
                teste:
                {
                  Acess:
                  {
                    Edit: true,
                    View: false
                  }
                },
                teste1:
                {
                  Acess:
                  {
                    Edit: false,
                    View: false
                  }
                }
              };
              
              console.log(find(fields,'teste'));
              
              function find(fields,field) {
                for(key in fields) {
                  if(key == field) {
                    return true;
                  }
                }
                return false;
              }
              

              如果你有一个对象里面有多个对象,如果你想知道某个对象是否包含在主对象上,只需使用find(MasterObject, 'Object to Search')。此函数将返回响应是否存在(TRUE 或 FALSE)。我希望对此有所帮助 - 可以在 JSFiddle 上查看示例。

              【讨论】:

              • 添加一些解释,说明此答案如何帮助 OP 解决当前问题
              • @ρяσѕρєяK,谢谢你的建议,我已经添加了解释:)
              【解决方案14】:
              let indexOf = -1;
              let theProperty = "value"
              let searchFor = "something";
              
              theArray.every(function (element, index) {
              
                  if (element[theProperty] === searchFor) {
                      indexOf = index;
                      return false;
                  }
                  return true;
              });
              

              【讨论】:

                【解决方案15】:
                collection.findIndex(item => item.value === 'smth') !== -1
                

                【讨论】:

                • 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性 cmets 挤满你的代码,因为这会降低代码和解释的可读性!
                • 解释一下。您可以edit your answer(但没有“编辑:”、“更新:”或类似的 - 答案应该看起来好像是今天写的)。
                【解决方案16】:
                var index = Data.findIndex(item => item.name == "John")
                

                这是一个简化版:

                var index = Data.findIndex(function(item){ return item.name == "John"})
                

                来自mozilla.org:

                findIndex() 方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回 -1。

                【讨论】:

                • 使用 "===" 进行字符串比较,这是这个答案中唯一缺少的东西。
                • @BrunoTavares,您认为在这种情况下哪种情况会有所不同?
                • @edank 如果 OP 要检查 token 字段而不是 name 字段,则可能会出现问题,因为 Data[0].token == 312312 的计算结果为 true,但 Data[0].token === 321321 的计算结果为 @987654330 @.
                • @edank 看看这个答案stackoverflow.com/questions/359494/…
                【解决方案17】:

                如果您在使用 Internet Explorer 时遇到问题,可以使用从 9.0 开始支持的 map() 函数:

                var index = Data.map(item => item.name).indexOf("Nick");
                

                【讨论】:

                【解决方案18】:

                如果你想获取属性令牌的值那么你也可以试试这个:

                    let data=[
                      { id_list: 1, name: 'Nick', token: '312312' },
                      { id_list: 2, name: 'John', token: '123123' },
                    ]
                
                    let resultingToken =  data[_.findKey(data,['name','John'])].token
                
                

                其中 _.findKey 是 Lodash 函数。

                【讨论】:

                  【解决方案19】:

                  使用Underscore.js:

                  var index = _.indexOf(_.pluck(item , 'name'), 'Nick');
                  

                  【讨论】:

                    【解决方案20】:

                    您可以在Lodash 库中使用findIndex。

                    示例:

                    var users = [
                    { 'user': 'barney',  'active': false },
                    { 'user': 'fred',    'active': false },
                    { 'user': 'pebbles', 'active': true }
                                ];
                    
                    _.findIndex(users, function(o) { return o.user == 'barney'; });
                    // => 0
                    
                    // The `_.matches` iteratee shorthand.
                    _.findIndex(users, { 'user': 'fred', 'active': false });
                    // => 1
                    
                    // The `_.matchesProperty` iteratee shorthand.
                    _.findIndex(users, ['active', false]);
                    // => 0
                    
                    // The `_.property` iteratee shorthand.
                    _.findIndex(users, 'active');
                    // => 2
                    

                    【讨论】:

                      【解决方案21】:

                      你可以使用过滤方法

                       const filteredData = data.filter(e => e.name !== 'john');
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 2022-11-10
                        • 2014-10-20
                        • 2023-04-08
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2021-10-18
                        相关资源
                        最近更新 更多