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


108

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

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

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

如何获得所有实例的信息?

Answers:


115

.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;
}

1
它似乎不是for用索引数组填充的单循环的更快替代方法。
2013年

1
@VisioN-是的,遍历数组的普通for循环也将更简单,但是由于OP提到尝试使用.indexOf(),所以我想证明它可以完成这项工作。(我想我认为OP可以弄清楚如何使用for循环来完成它。)当然,还有其他方法可以做到这一点,例如Cars.reduce(function(a, v, i) { if (v==="Nano") a.push(i); return a; }, []);
nnnnnn 2013年

我可以告诉您来自北美,因为您使用的indexes不是indices:P
4castle '16

2
@ 4castle-哈 不,我不是。“索引”和“索引”都是正确的,我倾向于在两者之间交替。我从未想过这是地区性方言。有趣。
nnnnnn 2016年

请注意,给出的第一个示例非常适合字符串和数组。第二个仅适用于数组。
赛斯怀特

80

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


2
+1。有趣的巧合:我只是编辑了我对答复下您的评论的答复,以提出确切的解决方案,然后刷新,看到您已经用相同的名称编码了相同的内容。
nnnnnn 2013年

@nnnnnn :)是的,我想可能reduce是一个不错的选择。
2013年

26
array.reduce((a, e, i) => (e === value) ? a.concat(i) : a, [])
yckart '16

我用google搜索contat的速度慢于push,因此我坚持答案。
安德烈·埃里克

54

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

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

3
很好,很有效。你能解释一下什么是过滤器(串)的角色
Muthamizhchelvan。V

2
@Muthu map(…)在每次迭代中检查e和的相等性value。当它们匹配时,返回索引,否则返回一个空字符串。要摆脱那些虚假的值,请filter(String)确保结果仅包含字符串类型的值,并且不为空。filter(String)也可以写成:filter(e => e !== '')
yckart

3
...或:将String(thing)任何内容强制转换为字符串。Array#filter返回条件为true的所有值的数组。因为空字符串是falsy,所以它们不包含在数组中。
yckart '18

谢谢你的解释,这是真正有用的,我
Muthamizhchelvan。V

2
如果我在项目中看到这个,我会感到困惑。读起来就像“过滤字符串”,这意味着仅当它是字符串时才保留。然后,结果数组将是作为字符串而不是数字的索引。
迈克尔·皮尔森

14

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

12

您可以使用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 : []);

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);
}

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


4

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

您也可以使用forEach方法。

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

var result = [];

Cars.forEach((car, index) => car === 'Nano' ? result.push(index) : null)

3
const indexes = cars
    .map((car, i) => car === "Nano" ? i : null)
    .filter(i => i !== null)

1
索引是从零开始的,因此如果第一辆汽车是Nano,这将失败。
扎克·德尔文塔瑟

1
哦,看,您有一个解决方案,而我的解决方案就像它一样。在我花时间写我的书之前,我应该早就见过你的。我以为循环如此之多,“我可以在2秒内做出自己的回答”。
迈克尔·皮尔森

是的 这些大多过于复杂。很好的纠正。
Zac Delventhal '19

2

这对我有用:

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]

1

只是共享另一种方法,您也可以使用函数发生器来获得结果:

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'));


0

每当遇到条件“ arr [i] == value”时,我们都可以使用Stack并将“ 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(); 
    }
}

2
该问题被标记为javascript,而我的答案是Java相信的吗?
noggin182 '19

0
["a", "b", "a", "b"]
   .map((val, index) => ({ val, index }))
   .filter(({val, index}) => val === "a")
   .map(({val, index}) => index)

=> [0, 2]

请为代码编写必要的说明或内联注释。顺便说一句,您的解决方案确实有效,但它包含3次迭代...
JustWe

0

您可以使用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]

-1

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

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'))
)


-1

如果您打算使用下划线/破折号,则可以

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

_.chain(Cars).map((v, i)=> [i, v === "Nano"]).filter(v=>v[1]).map(v=>v[0]).value()

[0, 3, 5]

2
您实际上并不需要任何库:(["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"]).map((v, i)=> [i, v === "Nano"]).filter(v=>v[1]).map(v=>v[0])
edjroot
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.