如何在Javascript数组中通过键和值查找对象的索引

117

给定:

var peoples = [
  { "attr1": "bob", "attr2": "pizza" },
  { "attr1": "john", "attr2": "sushi" },
  { "attr1": "larry", "attr2": "hummus" }
];

需求:

查找属性attr === value所在对象的索引,例如attr1 === "john"attr2 === "hummus"

更新: 请认真阅读我的问题,我不想通过$.inArray查找对象,也不想获取特定对象属性的值。请考虑这一点并回答问题。谢谢!


1
可能是在JavaScript对象数组中按ID查找对象的重复问题。 - Felix Kling
3
是的,同样的用例,但我认为我的问题更通用,例如,如果您搜索的关键字不是“id”,那么命中率会更高。 - return1.at
@FelixKling 我认为这不是重复的问题,因为它试图获取索引而不是对象(你指向的问题没有解决我的问题,但这个问题解决了)。 - jcuenod
8个回答

228

函数式编程方法

现在所有时髦的程序员都在使用函数式编程(你好React用户),所以我想给出一个函数式的解决方案。在我看来,它比迄今为止提出的命令式的foreach循环要好得多,并且使用ES6语法非常优雅。

更新

现在有一种称为findIndex的好方法,它接受一个返回true/false的函数,根据数组元素是否匹配进行判断(如常规操作,需检查浏览器兼容性)。

var index = peoples.findIndex(function(person) {
  return person.attr1 == "john"
});

使用ES6语法,您可以编写以下内容:

var index = peoples.findIndex(p => p.attr1 == "john");

(旧的)函数式方法

摘要

如果你正在寻找 index,其中 peoples[index].attr1 == "john",请使用以下代码:

var index = peoples.map(function(o) { return o.attr1; }).indexOf("john");

解释

步骤 1

使用 .map() 函数,根据特定的键获取值的数组:

var values = object_array.map(function(o) { return o.your_key; });

上面的行将您从这里带走:

var peoples = [
  { "attr1": "bob", "attr2": "pizza" },
  { "attr1": "john", "attr2": "sushi" },
  { "attr1": "larry", "attr2": "hummus" }
];

到这里:

var values = [ "bob", "john", "larry" ];

第二步

现在我们只需要使用.indexOf() 来查找我们想要的键的索引(当然,这也是我们要查找的对象的索引):

var index = values.indexOf(your_value);

解决方案

我们将上述所有内容结合起来:

var index = peoples.map(function(o) { return o.attr1; }).indexOf("john");

或者,如果您更喜欢ES6语法:

var index = peoples.map((o) => o.attr1).indexOf("john");

演示:

var peoples = [
  { "attr1": "bob", "attr2": "pizza" },
  { "attr1": "john", "attr2": "sushi" },
  { "attr1": "larry", "attr2": "hummus" }
];

var index = peoples.map(function(o) { return o.attr1; }).indexOf("john");
console.log("index of 'john': " + index);

var index = peoples.map((o) => o.attr1).indexOf("larry");
console.log("index of 'larry': " + index);

var index = peoples.map(function(o) { return o.attr1; }).indexOf("fred");
console.log("index of 'fred': " + index);

var index = peoples.map((o) => o.attr2).indexOf("pizza");
console.log("index of 'pizza' in 'attr2': " + index);


我很遗憾IE不支持findIndex函数。 - wonsuc
现在假设你想知道在行{ "attr1": "bob", "attr2": "pizza" }中,pizza的索引是多少,即为“1”,你该如何做呢?或者,如果给定值为"pizza",你想知道相应的属性名称(即:attr2),并且我们在第0行,你该如何做呢? - John Galassi
也许它已经更新了。findIndex现在返回-1或找到的索引位置。 - knoxgon
伟大而高效的方法 <3 - Ahsan Khan

22

如果你想检查对象本身而不影响原型,请使用hasOwnProperty()

var getIndexIfObjWithOwnAttr = function(array, attr, value) {
    for(var i = 0; i < array.length; i++) {
        if(array[i].hasOwnProperty(attr) && array[i][attr] === value) {
            return i;
        }
    }
    return -1;
}

要包括原型属性,使用:

var getIndexIfObjWithAttr = function(array, attr, value) {
    for(var i = 0; i < array.length; i++) {
        if(array[i][attr] === value) {
            return i;
        }
    }
    return -1;
}

1
+1,但为什么不只返回i(而不是$.inArray(array[i], array);)? - Me.Name
1
为什么你使用 i += 1 而不是 i++ - Amberlamps
1
为什么要使用“array[i].hasOwnProperty(attr)”而不是“array[i][attr]”? - Alain BECKER
@AlainSaint-Etienne 是的,我已经根据您的评论更新了我的答案,请检查。 - return1.at
1
我建议在“for”循环后添加“return -1”,以防元素未被找到(类似于JavaScript的“indexOf”或jQuery的“$ .inArray”)。 - schellmax
显示剩余3条评论

8
使用jQuery的.each()方法

var peoples = [
  { "attr1": "bob", "attr2": "pizza" },
  { "attr1": "john", "attr2": "sushi" },
  { "attr1": "larry", "attr2": "hummus" }
];

$.each(peoples, function(index, obj) {
   $.each(obj, function(attr, value) {
      console.log( attr + ' == ' + value );
   });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

使用for循环

var peoples = [
  { "attr1": "bob", "attr2": "pizza" },
  { "attr1": "john", "attr2": "sushi" },
  { "attr1": "larry", "attr2": "hummus" }
];

for (var i = 0; i < peoples.length; i++) {
  for (var key in peoples[i]) {
    console.log(key + ' == ' + peoples[i][key]);
  }
}


链接已经失效。 - Alexander

6

虽然这不是直接回答你的问题,但我认为值得提一下,因为你的问题似乎适用于“通过名称在键值存储中获取东西”的一般情况。

如果你不受“peoples”实现方式的限制,一个更符合JavaScript风格的获取正确对象的方法可能是:

var peoples = {
  "bob":  { "dinner": "pizza" },
  "john": { "dinner": "sushi" },
  "larry" { "dinner": "hummus" }
};

// If people is implemented this way, then
// you can get values from their name, like :
var theGuy = peoples["john"];

// You can event get directly to the values
var thatGuysPrefferedDinner = peoples["john"].dinner;

希望这不是你想要的答案,但它可能会对那些对“键/值”问题感兴趣的人有所帮助。


这个并不符合我的使用情况,但或许对其他人有所帮助。我应该更新我的问题,以使更通用的属性名称更清晰明了。 - return1.at

4
function getIndexByAttribute(list, attr, val){
    var result = null;
    $.each(list, function(index, item){
        if(item[attr].toString() == val.toString()){
           result = index;
           return false;     // breaks the $.each() loop
        }
    });
    return result;
}

只是澄清一件事:“return false”可能看起来是不必要的。一个人可以没有它,但这是一个很好的优化,因为它会中断“$.each()”循环。干得好!另一方面,调用“.toString()”很奇怪(为什么不比较值?),如果“attr”在“item”上未定义或val为“null”,很可能会导致错误...或者我错过了使用“toString()”的非常好的理由? - Alain BECKER
我不太记得为什么要这样做,但好像是因为当值为数字时出现了一些冲突。 - davids

2
你可以通过扩展JavaScript将其变成可重用的方法:

你也可以通过扩展JavaScript将其变成可重用的方法:

Array.prototype.findIndexBy = function(key, value) {
    return this.findIndex(item => item[key] === value)
}

const peoples = [{name: 'john'}]
const cats = [{id: 1, name: 'kitty'}]

peoples.findIndexBy('name', 'john')
cats.findIndexBy('id', 1)


1

请按照以下方式操作:

var peoples = [
  { "name": "bob", "dinner": "pizza" },
  { "name": "john", "dinner": "sushi" },
  { "name": "larry", "dinner": "hummus" }
];

$.each(peoples, function(i, val) {
    $.each(val, function(key, name) {
        if (name === "john")
            alert(key + " : " + name);
    });
});

输出:

name : john

请参考在线演示


1
绝对不需要 jQuery。 - lukas

0
您可以使用lodash的findKey https://docs-lodash.com/v4/find-key/ 它适用于对象和数组。
示例:
import _findKey from 'lodash.findkey';

    var users = {
      'barney':  { 'age': 36, 'active': true },
      'fred':    { 'age': 40, 'active': false },
      'pebbles': { 'age': 1,  'active': true }
    };
     
    _findKey(users, () => o.age < 40);
    // => 'barney' (iteration order is not guaranteed)
     
    // The `_.matches` iteratee shorthand.
    _findKey(users, { 'age': 1, 'active': true });
    // => 'pebbles'
     
    // The `_.matchesProperty` iteratee shorthand.
    _findKey(users, ['active', false]);
    // => 'fred'
     
    // The `_.property` iteratee shorthand.
    _findKey(users, 'active');
    // => 'barney'

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