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

IT技术 javascript jquery arrays
2021-01-11 17:29:50

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

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

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

我如何为所有实例获取它?

6个回答

.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");

您并没有真正明确如何使用索引,因此我的函数将它们作为数组返回(如果找不到值,则返回一个空数组),但是您可以对各个索引值执行其他操作循环内。

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

另一种替代解决方案是使用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]

注意:检查方法浏览器兼容性reduce在需要时使用polyfill

我用谷歌搜索contat比 慢push,因此我坚持答案。
2021-03-12 17:29:50
@nnnnnn:)是的,我认为这可能reduce是一个不错的选择。
2021-03-27 17:29:50
是的,请不要concat在这里使用——您在每次回调时都分配了一个全新的数组对象,并将前一个对象扔进垃圾收集器中,而在可读性方面没有任何相应的好处。
2021-04-01 17:29:50
+1。有趣的巧合:我刚刚在我的答案下编辑了我对您评论的回复,以提出这个解决方案,然后我刷新并看到您已经编码了相同的东西,只有一个变量名称不同。
2021-04-04 17:29:50
array.reduce((a, e, i) => (e === value) ? a.concat(i) : a, [])
2021-04-09 17:29:50

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

var indices = array.map((e, i) => e === value ? i : '').filter(String)
谢谢你的解释,对我很有帮助
2021-03-15 17:29:50
太好了,它有效。你能解释一下过滤器的作用吗(字符串)
2021-03-18 17:29:50
如果我在一个项目中看到这个,我会感到困惑。它读起来像“过滤到字符串”,意思是只有当它是一个字符串时才保留。然后结果数组将作为字符串的索引,而不是数字。
2021-03-25 17:29:50
...或:将String(thing)任何内容强制转换为字符串。Array#filter返回条件为真的所有值的数组因为空字符串是假的,所以它们不包含在数组中。
2021-03-31 17:29:50
@Muthumap(…)检查每次迭代是否与e相等value当它们匹配时返回索引,否则返回空字符串。要摆脱那些虚假值,请filter(String)确保结果仅包含字符串类型的值而不是空值。filter(String)也可以写成:filter(e => e !== '')
2021-04-07 17:29:50

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

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 : []);

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); // []