【问题标题】:Get the index of the object inside an array, matching a condition获取数组内对象的索引,匹配条件
【发布时间】:2013-04-06 13:06:31
【问题描述】:

我有一个这样的数组:

[{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"},...]

如何在不遍历整个数组的情况下获取与条件匹配的对象的索引?

例如,给定prop2=="yutu",我想获取索引1

我看到了.indexOf(),但认为它用于像["a1","a2",...] 这样的简单数组。我还检查了$.grep(),但这会返回对象,而不是索引。

【问题讨论】:

标签: javascript jquery arrays


【解决方案1】:

如何获取匹配条件的对象的索引(无需遍历数组)?

你不能,某事必须遍历数组(至少一次)。

如果条件变化很大,那么您将不得不循环并查看其中的对象以查看它们是否符合条件。但是,在具有 ES5 功能的系统上(或者如果您安装了一个 shim),该迭代可以相当简洁地完成:

var index;
yourArray.some(function(entry, i) {
    if (entry.prop2 == "yutu") {
        index = i;
        return true;
    }
});

它使用新的(ish)Array#some function,它循环遍历数组中的条目,直到你给它的函数返回 true。我给它的函数保存匹配条目的索引,然后返回true 以停止迭代。

当然,也可以使用for 循环。 this other answer 涵盖了您的各种迭代选项。

但是,如果您总是要在此查找中使用相同的属性,并且如果属性值是唯一的,您可以只循环一次并创建一个对象来映射它们:

var prop2map = {};
yourArray.forEach(function(entry) {
    prop2map[entry.prop2] = entry;
});

(或者,同样,您可以使用for 循环或your other options 中的任何一个。)

那么如果你需要找到带有prop2 = "yutu"的条目,你可以这样做:

var entry = prop2map["yutu"];

我称之为“交叉索引”数组。当然,如果您删除或添加条目(或更改它们的 prop2 值),您也需要更新映射对象。

【讨论】:

  • 感谢您的解释! thg435 指出的 jQuery 解决方案符合我的要求...
【解决方案2】:

为什么你不想精确地迭代?新的Array.prototype.forEach 非常适合此用途!

如果需要,您可以使用二叉搜索树通过单个方法调用进行查找。这是 JS 中 BTree 和红黑搜索树的简洁实现 - https://github.com/vadimg/js_bintrees - 但我不确定你是否可以同时找到索引。

【讨论】:

    【解决方案3】:

    截至 2016 年,您应该为此使用 Array.findIndex(ES2015/ES6 标准):

    a = [
      {prop1:"abc",prop2:"qwe"},
      {prop1:"bnmb",prop2:"yutu"},
      {prop1:"zxvz",prop2:"qwrq"}];
        
    index = a.findIndex(x => x.prop2 ==="yutu");
    
    console.log(index);

    Google Chrome、Firefox 和 Edge 均支持此功能。对于 Internet Explorer,链接页面上有一个 polyfill。

    性能说明

    函数调用很昂贵,因此对于非常大的数组,一个简单的循环将比findIndex 执行得更好:

    let test = [];
    
    for (let i = 0; i < 1e6; i++)
        test.push({prop: i});
    
    
    let search = test.length - 1;
    let count = 100;
    
    console.time('findIndex/predefined function');
        let fn = obj => obj.prop === search;
    
        for (let i = 0; i < count; i++)
            test.findIndex(fn);
    console.timeEnd('findIndex/predefined function');
    
    
    console.time('findIndex/dynamic function');
        for (let i = 0; i < count; i++)
            test.findIndex(obj => obj.prop === search);
    console.timeEnd('findIndex/dynamic function');
    
    
    console.time('loop');
        for (let i = 0; i < count; i++) {
            for (let index = 0; index < test.length; index++) {
                if (test[index].prop === search) {
                    break;
                }
            }
        }
    console.timeEnd('loop');

    与大多数优化一样,这应谨慎应用,并且仅在实际需要时应用。

    【讨论】:

    • 我没有看到这里需要一个临时数组。只需使用迭代器函数关闭上下文并使用变量的事实。此外,非 jQuery 版本不起作用(假设它位于索引 0?)。 两种解决方案都进行了比所需更多的迭代,如果数组很大,这不太理想(尽管它太大而人类会注意到的几率很低,除非查找发生 很多)。
    • @thg435:仍然认为它有点像 Rube Goldberg 机器,一个简单的杠杆就可以解决问题。 :-) 但是,嘿,它有效!
    • 你能解释一下x =&gt; x.prop2=="yutu"如何与findIndex()一起工作吗?
    • @AbhayPai:和function(x) { return x.prop2=="yutu" }一样
    • 我喜欢使用 polyfill 的建议。然而,由于使用了箭头 / lambda 函数,即使使用 polyfill,所编写的代码在 IE11 中仍然失败。重写为index = a.findIndex(function (x) { return x.prop2 == "yutu" }) 修复了这个问题,因此使用 polyfill 代码,findIndex 在 IE11 中工作
    【解决方案4】:

    正如 TJ Crowder 所说,每个人都会有某种隐藏迭代,lodash 变成:

    var index = _.findIndex(array, {prop2: 'yutu'})
    

    【讨论】:

    • 虽然你可以通过各种方式循环获取索引,但发现Index是最好的解决方案,甚至在ES6中采用原生数组方法
    【解决方案5】:

    您可以通过以下方式使用Array.prototype.some()(如其他答案中所述):

    https://jsfiddle.net/h1d69exj/2/

    function findIndexInData(data, property, value) {
        var result = -1;
        data.some(function (item, i) {
            if (item[property] === value) {
                result = i;
                return true;
            }
        });
        return result;
    }
    var data = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
    
    
    
    alert(findIndexInData(data, 'prop2', "yutu")); // shows index of 1
    

    【讨论】:

      【解决方案6】:
      var index;
      yourArray.some(function (elem, i) {
          return elem.prop2 === 'yutu' ? (index = i, true) : false;
      });
      

      遍历数组的所有元素。 如果条件不匹配,则返回索引和真或假。

      重要的是明确的返回值真(或布尔结果为真的值)。单个赋值是不够的,因为可能的索引为 0 (Boolean(0) === false),这不会导致错误但会禁用迭代的中断。

      编辑

      上面的一个更短的版本:

      yourArray.some(function (elem, i) {
          return elem.prop2 === 'yutu' && ~(index = i);
      });
      

      【讨论】:

      • 在你的第二个 sn-p 中 ~ 角色做了什么?
      • @serkan,它是一个bitwise NOT | 运算符,它是从索引(带-1)获取truthy/falsy 结果的简短版本,如果索引存在。
      • 感谢 Nina,没有 ~ 字符,代码照原样工作,不是吗?
      • @serkan,你的问题不清楚,但没有~,它就不会那样工作。
      • 哦,!!(index = 0)!!~(index = 0) 确实不同。谢谢!
      【解决方案7】:

      使用 Array.reduce() 的一步 - 没有 jQuery

      var items = [{id: 331}, {id: 220}, {id: 872}];
      
      var searchIndexForId = 220;
      var index = items.reduce(function(searchIndex, item, index){
        if(item.id === searchIndexForId) { 
          console.log('found!');
          searchIndex = index;
        }
        return searchIndex;
      }, null);
      

      如果未找到索引,将返回 null

      【讨论】:

        【解决方案8】:
        var list =  [
                        {prop1:"abc",prop2:"qwe"},
                        {prop1:"bnmb",prop2:"yutu"},
                        {prop1:"zxvz",prop2:"qwrq"}
                    ];
        
        var findProp = p => {
            var index = -1;
            $.each(list, (i, o) => {
                if(o.prop2 == p) {
                    index = i;
                    return false; // break
                }
            });
            return index; // -1 == not found, else == index
        }
        

        【讨论】:

          【解决方案9】:
          function findIndexByKeyValue(_array, key, value) {
              for (var i = 0; i < _array.length; i++) { 
                  if (_array[i][key] == value) {
                      return i;
                  }
              }
              return -1;
          }
          var a = [
              {prop1:"abc",prop2:"qwe"},
              {prop1:"bnmb",prop2:"yutu"},
              {prop1:"zxvz",prop2:"qwrq"}];
          var index = findIndexByKeyValue(a, 'prop2', 'yutu');
          console.log(index);
          

          【讨论】:

            【解决方案10】:

            Georg 已经提到 ES6 有 Array.findIndex 。 其他一些答案是 ES5 使用 Array.some 方法的解决方法。

            一种更优雅的方法可以是

            var index;
            for(index = yourArray.length; index-- > 0 && yourArray[index].prop2 !== "yutu";);
            

            同时我想强调,Array.some 可以用二进制或其他有效的搜索技术来实现。因此,它在某些浏览器中可能比 for 循环表现更好。

            【讨论】:

              【解决方案11】:
              var CarId = 23;
              
              //x.VehicleId property to match in the object array
              var carIndex = CarsList.map(function (x) { return x.VehicleId; }).indexOf(CarId);
              

              对于基本的数组编号,您也可以这样做:

              var numberList = [100,200,300,400,500];
              var index = numberList.indexOf(200); // 1
              

              如果在数组中找不到值,你会得到-1。

              【讨论】:

                【解决方案12】:

                我在上面看到了很多解决方案。

                这里我使用map函数在数组对象中查找搜索文本的索引。

                我将使用学生数据来解释我的答案。

                • 第一步:为学生创建数组对象(可选,您可以创建自己的数组对象)。
                  var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

                • 第 2 步:创建变量以搜索文本
                  var studentNameToSearch = "Divya";

                • 第 3 步:创建变量来存储匹配的索引(这里我们使用 map 函数进行迭代)。
                  var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

                var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];
                
                var studentNameToSearch = "Divya";
                
                var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);
                
                console.log(matchedIndex);
                
                alert("Your search name index in array is:"+matchedIndex)

                【讨论】:

                  【解决方案13】:

                  试试这个代码

                  var x = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
                  let index = x.findIndex(x => x.prop1 === 'zxvz')
                  

                  【讨论】:

                    【解决方案14】:

                    另一个简单的方法是:

                     function getIndex(items) {
                            for (const [index, item] of items.entries()) {
                                if (item.prop2 === 'yutu') {
                                    return index;
                                }
                            }
                        }
                    
                    const myIndex = getIndex(myArray);
                    

                    【讨论】:

                      【解决方案15】:

                      使用Array.map()Array.indexOf(string)

                      const arr = [{
                        prop1: "abc",
                        prop2: "qwe"
                      }, {
                        prop1: "bnmb",
                        prop2: "yutu"
                      }, {
                        prop1: "zxvz",
                        prop2: "qwrq"
                      }]
                      
                      const index = arr.map(i => i.prop2).indexOf("yutu");
                      
                      console.log(index);

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-01-02
                        • 1970-01-01
                        • 2019-08-11
                        • 1970-01-01
                        • 2022-07-10
                        相关资源
                        最近更新 更多