获取数组内对象的索引,匹配条件

IT技术 javascript jquery arrays
2021-01-15 09:18:26

我有一个这样的数组:

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

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

例如,给定prop2=="yutu",我想获得 index 1

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

6个回答

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

与大多数优化一样,这应该谨慎应用,并且仅在实际需要时才应用。

我在这里没有看到需要临时数组。只需使用迭代器函数关闭上下文并使用变量的事实。此外,非 jQuery 版本不起作用(假设它在 index 处找到0?)。两种解决方案的迭代次数都比所需的多,如果数组很大,这不太理想(尽管人类会注意到它太大的几率很低,除非查找发生很多)。
2021-03-19 09:18:26
@AbhayPai:与 function(x) { return x.prop2=="yutu" }
2021-03-20 09:18:26
我喜欢使用 polyfill 的建议。然而,由于使用了箭头 / lambda 函数,即使使用 polyfill,所编写的代码在 IE11 中仍然失败。重新编写index = a.findIndex(function (x) { return x.prop2 == "yutu" })修复了问题,以便使用 polyfill 代码,findIndex 在 IE11 中工作
2021-04-02 09:18:26
@ thg435:仍然认为它有点像 Rube Goldberg 机器,一个简单的杠杆就可以做到这一点。:-) 但是,嘿,它有效!
2021-04-08 09:18:26
你能解释一下x => x.prop2=="yutu"findIndex() 是如何工作的吗?
2021-04-09 09:18:26

如何获取与条件匹配的对象的索引(不沿数组迭代)?

你不能,有些东西必须遍历数组(至少一次)。

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

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

这使用了 new(ish)Array#some函数,它循环遍历数组中的条目,直到您给它的函数返回 true。我给它的函数保存匹配条目的索引,然后返回true以停止迭代。

或者当然,只需使用for循环。这个其他答案涵盖了您的各种迭代选项

但是,如果您始终要在此查找中使用相同的属性,并且属性值是唯一的,则您只需循环一次并创建一个对象来映射它们:

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

(或者,同样,您可以使用for循环或任何其他选项。)

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

var entry = prop2map["yutu"];

我称之为“交叉索引”数组。自然地,如果您删除或添加条目(或更改它们的prop2值),您也需要更新您的映射对象。

感谢您的解释!jQuery 指向的解决方案thg435做了我想要的......
2021-04-01 09:18:26

TJ Crowder 所说的,每个地方都会有某种隐藏的迭代,用lodash这变成:

var index = _.findIndex(array, {prop2: 'yutu'})
虽然您可以通过各种方式循环获取索引,但 find Index 是最好的解决方案,甚至在 ES6 中采用了原生数组方法
2021-03-24 09:18:26
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。

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

迭代数组的所有元素。如果条件不匹配,则返回索引和 true 或 false。

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

编辑

上面更短的版本:

yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' && ~(index = i);
});
谢谢 Nina,没有 ~ 字符,代码可以正常工作,不是吗?
2021-03-15 09:18:26
哦,!!(index = 0)!!~(index = 0)差异确实如此。谢谢!
2021-03-16 09:18:26
@serkan,它是一个按位非|运算符,如果索引存在,它是从索引(带 -1)获取真/结果的简短版本
2021-03-17 09:18:26
~ 字符在你的第二个片段中做了什么?
2021-03-23 09:18:26
@serkan,你的问题不清楚,但没有~它就不能那样工作。
2021-04-03 09:18:26