如何在数组中找到所有元素出现的索引?

nor*_*dum 94 javascript arrays jquery

我试图在JavaScript数组中找到元素的所有实例的索引,比如"Nano".

var Cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];
Run Code Online (Sandbox Code Playgroud)

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

我如何获得所有实例?

nnn*_*nnn 100

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

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");
Run Code Online (Sandbox Code Playgroud)

你没有真正说明你想如何使用索引,所以我的函数将它们作为一个数组返回(如果找不到值,则返回一个空数组),但是你可以用单独的索引值做其他事情.在循环内.

更新:根据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;
}
Run Code Online (Sandbox Code Playgroud)

  • 它似乎并不是比填充索引数组的单个“for”循环更快的替代方案。 (2认同)
  • @VisioN - 是的,一个简单的 for 循环迭代数组也会更简单,但由于 OP 提到尝试使用 `.indexOf()` 我想证明它可以完成这项工作。(我想我认为OP可以弄清楚如何使用for循环来做到这一点。)当然还有其他方法可以做到这一点,例如`Cars.reduce(function(a, v, i) { if (v= ==“纳米”)a.push(i);返回a;},[]);` (2认同)
  • @ 4castle - 哈.不,我不是."指数"和"指数"都是正确的,我倾向于在两者之间交替.我从来没有想过这是区域方言的事情.有趣. (2认同)

Vis*_*ioN 69

另一种替代解决方案是使用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]
Run Code Online (Sandbox Code Playgroud)

注意:检查方法的浏览器兼容性,reduce并根据需要使用polyfill.

  • `array.reduce((a,e,i)=>(e === value)?a.concat(i):a,[])` (24认同)
  • 我用谷歌搜索“contat”比“push”慢,因此我坚持答案。 (3认同)
  • +1。有趣的巧合:我只是编辑了我对回答下您的评论的答复,以提出确切的解决方案,然后刷新,看到您已经用相同的名称编码了相同的内容。 (2认同)
  • 是的,请不要在这里使用“concat”——您在每个回调上分配一个全新的数组对象,并将前一个对象扔进垃圾收集器,而在可读性方面没有任何相应的好处。 (2认同)
  • @Darkproduct 解决方案将不起作用。Push 方法返回一个数字(数组的长度)而不是数组本身。所以它会引发错误。请参阅:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push (2认同)

yck*_*art 42

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

var indices = array.map((e, i) => e === value ? i : '').filter(String)
Run Code Online (Sandbox Code Playgroud)

  • ...或:`String(thing)`将任何内容强制转换为字符串。Array#filter返回条件为[truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy)的所有值的数组。因为空字符串是[falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy),所以它们不包含在数组中。 (3认同)
  • 很好,很有效。你能解释一下filter(String)的作用是什么 (2认同)
  • @Muthu`map(...)`检查每次迭代的"e"和"value"是否相等.当它们匹配时返回索引,否则返回一个空字符串.为了摆脱那些虚假的值,`filter(String)`确保结果只包含string类型的值,而不是空的.`filter(String)`也可以写成:`filter(e => e!=='')` (2认同)
  • 如果我在项目中看到这个我会很困惑。它读起来像“过滤到字符串”,意思是仅保留字符串。然后生成的数组将是字符串索引,而不是数字。 (2认同)

Zac*_*hal 9

您可以使用map和编写一个简单易读的解决方案filter

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

编辑:如果您不需要支持IE / Edge(或正在转译您的代码),则ES2019给了我们flatMap,它使您能够以一种简单的方式进行此操作:

const nanoIndexes = Cars.flatMap((car, i) => car === 'Nano' ? i : []);
Run Code Online (Sandbox Code Playgroud)


Ted*_*Khi 8

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

您也可以使用 forEach 方法。

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

var result = [];

Cars.forEach((car, index) => car === 'Nano' ? result.push(index) : null)
Run Code Online (Sandbox Code Playgroud)


Mik*_*hev 7

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); // []
Run Code Online (Sandbox Code Playgroud)


aba*_*ter 6

注意:MDN提供了一个使用while循环方法

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);
}
Run Code Online (Sandbox Code Playgroud)

我不会说这比其他答案更好。真有趣。