获取数组中符合条件的对象的索引

538

我有一个像这样的数组:

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

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

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

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


1
如果您想找到所有匹配的索引,请查看 - https://dev59.com/L8Pra4cB1Zd3GeqPWwV1 - Manu
16个回答

1175

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

与大多数优化一样,这种优化应谨慎应用,仅在确实需要时使用。


3
在这里我看不到需要使用临时数组。只需利用迭代函数闭合上下文所需的变量即可。另外,非jQuery版本无法工作(假设找到索引为“0”?)。两种解决方案都进行了比所需更多的迭代,如果数组很大,则不太理想(虽然除非频繁发生查找,否则人类注意到它很大的几率很低)。 - T.J. Crowder
小提示:使用jQuery.map来避免插件冲突 :)作为自我规定,我总是避免使用$。 - Nickvda
4
你能否解释一下如何在findIndex()中使用x => x.prop2=="yutu"的语法? 该语法是一种箭头函数,可以作为findIndex()方法的参数。在此语法中,变量x代表数组中的每个元素,箭头后面的代码表示返回一个布尔值(true或false),以指示是否找到符合条件的元素。具体而言,x.prop2指的是元素对象中名为"prop2"的属性,"=="表示比较它的值是否等于"yutu"。当该条件成立时,findIndex()将返回第一个符合条件的元素的索引;否则,返回-1表示未找到符合条件的元素。 - Abhay Pai
7
@AbhayPai说的是和function(x) { return x.prop2=="yutu" }一样的意思。 - georg
7
我喜欢使用polyfill的建议。然而,即使使用polyfill,由于箭头/lambda函数的使用,该代码在IE11中仍会失败。重写为index = a.findIndex(function (x) { return x.prop2 == "yutu" })解决了这个问题,因此在使用polyfill的代码中,findIndex可以在IE11中工作。 - Rick Glos
显示剩余5条评论

34

如何获取符合条件的对象的索引(不用遍历整个数组)?

你无法做到,至少需要对数组进行一次迭代。

如果条件经常变化,那么您将不得不循环遍历并查看其中的对象是否与条件匹配。然而,在具有ES5功能的系统上(或者如果您安装了shim),该迭代可以相当简洁地完成:

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

这里使用了相对较新的Array#some函数,它会遍历数组中的每个元素,直到传递给它的函数返回true。我所提供的函数会保存匹配项的索引,然后返回true以停止迭代。

当然,您也可以使用for循环。您可以在这个答案中找到各种迭代选项。

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

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

(或者,你可以使用for循环或其他选项。)

然后,如果您需要查找带有prop2 = "yutu"的条目,您可以这样做:

var entry = prop2map["yutu"];

我将此称为“跨索引”该数组。如果您删除或添加条目(或更改它们的prop2值),则还需要更新映射对象。


谢谢您的解释!thg435 指出的使用 jQuery 的解决方案实现了我的目标... - amp

28

TJ Crowder所说的,任何方法都会有某种隐藏的迭代方式,使用lodash,变得更简单:

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

1
虽然你可以通过循环遍历来获取索引的各种方式,但是使用findIndex是最好的解决方案,甚至在ES6中被采用为原生数组方法。 - Kelly Milligan

19
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。


13
var index;
yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' ? (index = i, true) : false;
});

迭代遍历数组的所有元素。如果条件不满足,它将返回索引和false,否则返回索引和true。

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

编辑

以上内容的更简短版本:

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

@serkan,这是一个按位非|运算符,它是通过索引(带有-1)获取真值/伪值结果的简短版本,如果索引存在的话。 - Nina Scholz
谢谢Nina,没有波浪符号,代码就可以正常工作了,是吧? - serkan
@serkan,你的问题不明确,但是没有~它就不能这样工作。 - Nina Scholz
我只是看不出它的意义,为什么你需要波浪符号。没有波浪符号,代码的功能是一样的。也许我漏掉了什么... - serkan
1
哦,!!(index = 0)!!~(index = 0) 的确有区别。谢谢! - serkan
显示剩余5条评论

12
使用 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);


9

最好且最快的方法是:

const products = [
  { prop1: 'telephone', prop2: 996 },
  { prop1: 'computadora', prop2: 1999 },
  { prop1: 'bicicleta', prop2: 995 },
];

const index = products.findIndex(el => el.prop2 > 1000);

console.log(index); // 1

5

我已经看到了上面提出的许多解决方案。

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

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

  • 步骤1:为学生创建数组对象(可以自己创建),示例如下:
    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)


3
你可以按照以下方式使用 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

3

试试这段代码

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接