【问题标题】:How to find index of all occurrences of element in array?如何查找数组中所有出现的元素的索引?
【发布时间】:2014-01-14 21:57:21
【问题描述】:

我正在尝试在 JavaScript 数组中查找元素的所有实例的索引,例如“Nano”。

var Cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];

我试过jQuery.inArray,或者类似的.indexOf(),但它只给出了元素最后一个实例的索引,在这种情况下是5。

如何为所有实例获取它?

【问题讨论】:

    标签: javascript jquery arrays


    【解决方案1】:

    .indexOf() method 有一个可选的第二个参数,指定开始搜索的索引,因此您可以在循环中调用它来查找特定值的所有实例:

    function getAllIndexes(arr, val) {
        var indexes = [], i = -1;
        while ((i = arr.indexOf(val, i+1)) != -1){
            indexes.push(i);
        }
        return indexes;
    }
    
    var indexes = getAllIndexes(Cars, "Nano");
    

    您并没有明确说明要如何使用索引,因此我的函数将它们作为数组返回(如果未找到值,则返回空数组),但您可以使用循环内的各个索引值。

    更新:根据 VisioN 的评论,一个简单的 for 循环可以更有效地完成相同的工作,并且更易于理解,因此更易于维护:

    function getAllIndexes(arr, val) {
        var indexes = [], i;
        for(i = 0; i < arr.length; i++)
            if (arr[i] === val)
                indexes.push(i);
        return indexes;
    }
    

    【讨论】:

    • 它似乎不是填充索引数组的单个 for 循环的更快替代方案。
    • @VisioN - 是的,一个简单的 for 循环遍历数组也会更简单,但是由于 OP 提到尝试使用 .indexOf() 我想证明它可以完成这项工作。 (我想我认为 OP 可以弄清楚如何使用 for 循环来做到这一点。)当然还有其他方法可以做到这一点,例如,Cars.reduce(function(a, v, i) { if (v==="Nano") a.push(i); return a; }, []);
    • 我可以告诉你来自北美,因为你使用 indexes 而不是 indices :P
    • @4castle - 哈。不,我不是。 “索引”和“索引”都是正确的,我倾向于在两者之间交替。我从来没有想过这是地方方言的事情。有趣。
    • @IgorFomenko - 感谢您的建议。这不是真正的“计算”,它只是一个属性查找,但实际上我仍然经常根据你的建议编写循环代码,但如果它与问题没有直接关系,我通常不会在 StackOverflow 答案中这样做。您有多确定 JS 编译器不会在幕后自动进行优化?
    【解决方案2】:

    另一种替代解决方案是使用Array.prototype.reduce()

    ["Nano","Volvo","BMW","Nano","VW","Nano"].reduce(function(a, e, i) {
        if (e === 'Nano')
            a.push(i);
        return a;
    }, []);   // [0, 3, 5]
    

    注意:检查browser compatibilityreduce 方法并在需要时使用polyfill

    【讨论】:

    • +1。有趣的巧合:我刚刚在我的回答下编辑了对您的评论的回复,以确切地建议这个解决方案,然后我刷新并看到您已经编写了相同的东西,只有一个变量名称不同。
    • @nnnnnn :) 是的,我想reduce 可能是一个不错的选择。
    • array.reduce((a, e, i) =&gt; (e === value) ? a.concat(i) : a, [])
    • 我用谷歌搜索了contatpush 慢,所以我坚持这个答案。
    • 是的,请不要在这里使用concat——你在每个回调中分配一个全新的数组对象,并将前一个对象扔到垃圾收集器中,而没有任何相称的可读性好处。
    【解决方案3】:

    使用Array.prototype.map()Array.prototype.filter() 的另一种方法:

    var indices = array.map((e, i) => e === value ? i : '').filter(String)
    

    【讨论】:

    • 很好,它有效。你能解释一下filter(String)的作用是什么
    • @Muthu map(…) 在每次迭代中检查evalue 的相等性。当它们匹配时返回索引,否则返回空字符串。为了摆脱那些虚假的值,filter(String) 确保结果只包含字符串类型的值而不是空值。 filter(String) 也可以写成:filter(e =&gt; e !== '')
    • ...或:String(thing) 将任何内容强制转换为字符串。 Array#filter 返回条件为truthy 的所有值的数组。因为空字符串是falsy,所以它们不包含在数组中。
    • 谢谢你的解释,对我很有帮助
    • 如果我在项目中看到这个我会很困惑。它读起来像“过滤到字符串”,意思是只有当它是一个字符串时才保留。然后生成的数组将是字符串的索引,而不是数字。
    【解决方案4】:

    您可以同时使用mapfilter 来编写一个简单易读的解决方案:

    const nanoIndexes = Cars
      .map((car, i) => car === 'Nano' ? i : -1)
      .filter(index => index !== -1);
    

    编辑:如果您不需要支持 IE/Edge(或正在转译您的代码),ES2019 给了我们flatMap,它让您可以在一个简单的单行中做到这一点:

    const nanoIndexes = Cars.flatMap((car, i) => car === 'Nano' ? i : []);
    

    【讨论】:

      【解决方案5】:

      es6 风格更简单。

      const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);
      
      
      //Examples:
      var cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];
      indexOfAll(cars, "Nano"); //[0, 3, 5]
      indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3]
      indexOfAll([1, 2, 3], 4); // []
      

      【讨论】:

        【解决方案6】:

        我只想用另一种简单的方法更新。

        您也可以使用 forEach 方法。

        var Cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];
        
        var result = [];
        
        Cars.forEach((car, index) => car === 'Nano' ? result.push(index) : null)
        

        【讨论】:

          【解决方案7】:

          注意:MDN 给出了method using a while loop

          var indices = [];
          var array = ['a', 'b', 'a', 'c', 'a', 'd'];
          var element = 'a';
          var idx = array.indexOf(element);
          while (idx != -1) {
            indices.push(idx);
            idx = array.indexOf(element, idx + 1);
          }
          

          我不会说它比其他答案更好。很有趣。

          【讨论】:

            【解决方案8】:
            const indexes = cars
                .map((car, i) => car === "Nano" ? i : null)
                .filter(i => i !== null)
            

            【讨论】:

            • 索引是从零开始的,所以如果第一辆车是 Nano,这将失败。
            • 哦,看,你有一个解决方案,我的看起来就像它一样。在我花时间写我的之前,我应该看到你的。我想,有这么多庞大的 for 循环,“我可以在 2 秒内做出自己的答案。”
            • 是的。这些大多过于复杂。很好的修正。
            【解决方案9】:

            这对我有用:

            let array1 = [5, 12, 8, 130, 44, 12, 45, 12, 56];
            let numToFind = 12
            let indexesOf12 = [] // the number whose occurrence in the array we want to find
            
            array1.forEach(function(elem, index, array) {
                if (elem === numToFind) {indexesOf12.push(index)}
                return indexesOf12
            })
            
            console.log(indexesOf12) // outputs [1, 5, 7]
            

            【讨论】:

              【解决方案10】:

              只是为了分享另一种方法,你也可以使用Function Generators来实现结果:

              function findAllIndexOf(target, needle) {
                return [].concat(...(function*(){
                  for (var i = 0; i < target.length; i++) if (target[i] === needle) yield [i];
                })());
              }
              
              var target = "hellooooo";
              var target2 = ['w','o',1,3,'l','o'];
              
              console.log(findAllIndexOf(target, 'o'));
              console.log(findAllIndexOf(target2, 'o'));

              【讨论】:

                【解决方案11】:
                ["a", "b", "a", "b"]
                   .map((val, index) => ({ val, index }))
                   .filter(({val, index}) => val === "a")
                   .map(({val, index}) => index)
                
                => [0, 2]
                

                【讨论】:

                • 请为代码写一个必要的解释或内联 cmets。顺便说一句,您的解决方案确实有效,但它包含 3 次迭代......
                【解决方案12】:

                你可以使用 Polyfill

                if (!Array.prototype.filterIndex) {
                Array.prototype.filterIndex = function (func, thisArg) {
                
                    'use strict';
                    if (!((typeof func === 'Function' || typeof func === 'function') && this))
                        throw new TypeError();
                
                    let len = this.length >>> 0,
                        res = new Array(len), // preallocate array
                        t = this, c = 0, i = -1;
                
                    let kValue;
                    if (thisArg === undefined) {
                        while (++i !== len) {
                            // checks to see if the key was set
                            if (i in this) {
                                kValue = t[i]; // in case t is changed in callback
                                if (func(t[i], i, t)) {
                                    res[c++] = i;
                                }
                            }
                        }
                    }
                    else {
                        while (++i !== len) {
                            // checks to see if the key was set
                            if (i in this) {
                                kValue = t[i];
                                if (func.call(thisArg, t[i], i, t)) {
                                    res[c++] = i;
                                }
                            }
                        }
                    }
                
                    res.length = c; // shrink down array to proper size
                    return res;
                };
                

                }

                像这样使用它:

                [2,23,1,2,3,4,52,2].filterIndex(element => element === 2)
                
                result: [0, 3, 7]
                

                【讨论】:

                  【解决方案13】:

                  findIndex 仅检索与回调输出匹配的第一个索引。您可以通过扩展 Array 来实现您自己的 findIndexes,然后将您的数组转换为新结构。

                  class EnhancedArray extends Array {
                    findIndexes(where) {
                      return this.reduce((a, e, i) => (where(e, i) ? a.concat(i) : a), []);
                    }
                  }
                     /*----Working with simple data structure (array of numbers) ---*/
                  
                  //existing array
                  let myArray = [1, 3, 5, 5, 4, 5];
                  
                  //cast it :
                  myArray = new EnhancedArray(...myArray);
                  
                  //run
                  console.log(
                     myArray.findIndexes((e) => e===5)
                  )
                  /*----Working with Array of complex items structure-*/
                  
                  let arr = [{name: 'Ahmed'}, {name: 'Rami'}, {name: 'Abdennour'}];
                  
                  arr= new EnhancedArray(...arr);
                  
                  
                  console.log(
                    arr.findIndexes((o) => o.name.startsWith('A'))
                  )

                  【讨论】:

                    【解决方案14】:

                    我们可以使用Stack,每次遇到条件“arr[i]==value”时将“i”压入栈

                    检查一下:

                    static void getindex(int arr[], int value)
                    {
                        Stack<Integer>st= new Stack<Integer>();
                        int n= arr.length;
                        for(int i=n-1; i>=0 ;i--)
                        {
                            if(arr[i]==value)
                            {
                                st.push(i);
                            }
                        }   
                        while(!st.isEmpty())
                        {
                            System.out.println(st.peek()+" ");
                            st.pop(); 
                        }
                    }
                    

                    【讨论】:

                    • 问题标记为javascript,而您的答案是Java 我相信?
                    【解决方案15】:

                    当两个参数都作为数组传递时

                    
                        function getIndexes(arr, val) {
                            var indexes = [], i;
                            for(i = 0; i < arr.length; i++){
                        for(j =0; j< val.length; j++) {
                         if (arr[i] === val[j])
                                    indexes.push(i);
                        }
                        }    
                            return indexes;
                        }
                    
                    

                    【讨论】:

                      猜你喜欢
                      • 2019-07-12
                      • 2018-01-11
                      • 2018-09-25
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2016-06-09
                      • 1970-01-01
                      相关资源
                      最近更新 更多