如何通过值获取JavaScript对象中的键?

720

我有一个非常简单的JavaScript对象,我将其用作关联数组。是否有一个简单的函数可以让我获取值对应的键名,还是我必须手动迭代对象并找到它?


没有这样的标准函数可以实现这个功能。如果映射是真正的双向的,那么构建一个“翻转”的映射并对其进行索引就很容易了。否则,一个简单的属性迭代器(可能带有hasOwnProperty保护)和一个隐藏在函数内部的早期返回就可以很好地解决问题... - user166390
如果一个对象被多个键引用,这该怎么办呢? var o = []; var map = {first: o, second: o}find_key(o) 会返回什么? - Gareth
5
没问题 ;) 我只是打算将它用于具有唯一键值对的数组。 - arik
可能是获取JavaScript键/值对象键的最佳方法的重复问题。 - Andy
1
我已经制作了一个没有迭代的版本 https://dev59.com/kmkw5IYBdhLWcg3waZ74#36705765。测试所有建议的解决方案在jsfiddle上将是有趣的。 - Pawel
31个回答

17

如果你正在使用 UnderscoreLodash 库,你可以使用 _.findKey 函数:

var users = {
  'barney':  { 'age': 36, 'active': true },
  'fred':    { 'age': 40, 'active': false },
  'pebbles': { 'age': 1,  'active': true }
};

_.findKey(users, function(o) { return 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'

16

我创建了库(https://github.com/alethes/bimap),它实现了一个强大、灵活和高效的JavaScript双向映射接口。它没有任何依赖关系,并且既可以在服务器端使用(在Node.js中,您可以使用npm install bimap安装它),也可以在浏览器中使用(通过链接到lib/bimap.js)。

基本操作非常简单:

var bimap = new BiMap;
bimap.push("k", "v");
bimap.key("k") // => "v"
bimap.val("v") // => "k"

bimap.push("UK", ["London", "Manchester"]);
bimap.key("UK"); // => ["London", "Manchester"]
bimap.val("London"); // => "UK"
bimap.val("Manchester"); // => "UK"

在这两个方向上,键值映射的检索速度都非常快。在内部没有昂贵的对象/数组遍历,因此平均访问时间不受数据大小的影响而保持恒定。


唯一不需要迭代(无论是在解决方案本身、标准库还是其他库中)的解决方案之一。 - Scott Rudiger

14

这对我获取对象的键/值有效。

let obj = {
  'key1': 'value1',
  'key2': 'value2',
  'key3': 'value3',
  'key4': 'value4'
}

Object.keys(obj).map(function(k) {
  console.log("key with value: " + k + " = " + obj[k])
})


然而,那并没有回答问题。通常情况下,只有在需要其返回值时才应使用map,而不是作为一般迭代器。 - Dave Newton
这并没有回答问题,也就是说,“通过值获取键”。这个答案仅仅展示了如何通过键来迭代一个对象。 - Jason

8

没有看到以下内容:

const obj = {
  id: 1,
  name: 'Den'
};

function getKeyByValue(obj, value) {
  return Object.entries(obj).find(([, name]) => value === name);
}

const [ key ] = getKeyByValue(obj, 'Den');
console.log(key)
  


5

给定 input={"a":"x", "b":"y", "c":"x"} ...

  • 使用第一个值(例如output={"x":"a","y":"b"}):

input = {
  "a": "x",
  "b": "y",
  "c": "x"
}
output = Object.keys(input).reduceRight(function(accum, key, i) {
  accum[input[key]] = key;
  return accum;
}, {})
console.log(output)

  • 使用最后一个值(例如:output={"x":"c","y":"b"}):

input = {
  "a": "x",
  "b": "y",
  "c": "x"
}
output = Object.keys(input).reduce(function(accum, key, i) {
  accum[input[key]] = key;
  return accum;
}, {})
console.log(output)

  • 获取每个值的键数组(例如output={"x":["c","a"],"y":["b"]}):

input = {
  "a": "x",
  "b": "y",
  "c": "x"
}
output = Object.keys(input).reduceRight(function(accum, key, i) {
  accum[input[key]] = (accum[input[key]] || []).concat(key);
  return accum;
}, {})
console.log(output)


1
这绝对是最好的答案,但我一直在想如何将其转换为仅返回给定对象的键,即在功能上等同于数组的indexOf。 - Souhaieb Besbes
除非内存受限并且您愿意花费大量处理能力多次查看对象,否则只需将“输出”保存为变量,并在其中查找结果… 如 output ['x']。这就是您所问的吗? - Fabio Beltramini

5

由于这些值是唯一的,因此将其作为附加密钥集添加应该是可能的。这可以通过以下简便方式完成。

var foo = {};
foo[foo.apple = "an apple"] = "apple";
foo[foo.pear = "a pear"] = "pear";

这将允许通过键或值进行检索:
var key = "apple";
var value = "an apple";

console.log(foo[value]); // "apple"
console.log(foo[key]); // "an apple"

这假设键和值之间没有共同元素。

1
唯一不需要迭代(无论是在解决方案本身、标准库还是其他库中)的解决方案之一。 - Scott Rudiger
1
OP确实说过键/值对都是唯一的,因此这个简单的答案非常棒!做得好 ;) - customcommander

4

这是对Underscorejs方法的一个小扩展,使用Lodash代替:

var getKeyByValue = function(searchValue) {
  return _.findKey(hash, function(hashValue) {
    return searchValue === hashValue;
  });
}

FindKey搜索并返回第一个与该值匹配的键
如果您想要最后一个匹配项,请改用FindLastKey


4

ES6 方法:

Object.fromEntries(Object.entries(a).map(b => b.reverse()))['value_you_look_for']

3

以下是我的解决方案:

例如,假设我们有一个包含三组值的对象:

function findKey(object, value) {

    for (let key in object)
        if (object[key] === value) return key;

    return "key is not found";
}

const object = { id_1: "apple", id_2: "pear", id_3: "peach" };

console.log(findKey(object, "pear"));
//expected output: id_2

我们可以简单地编写一个findKey(array, value)函数,它接收两个参数,一个是对象,另一个是你要查找的键的值。这样,该方法具有可重用性,你不需要每次手动迭代对象,只需传递两个参数即可使用该函数。


3
这里是一个 Lodash 的解决方案,适用于平面的key => value对象,而不是嵌套式对象。接受答案建议使用 _.findKey 处理有嵌套对象的对象,但在这种常见情况下无法工作。

此方法反转对象,交换键和值,然后通过查找新(反转)对象上的值来查找键。如果未找到键,则返回 false ,我更喜欢这个结果,而不是 undefined,但您可以轻松地通过getKey()中的_.get方法的第三个参数进行交换。

// Get an object's key by value
var getKey = function( obj, value ) {
 var inverse = _.invert( obj );
 return _.get( inverse, value, false );
};

// US states used as an example
var states = {
 "AL": "Alabama",
 "AK": "Alaska",
 "AS": "American Samoa",
 "AZ": "Arizona",
 "AR": "Arkansas",
 "CA": "California",
 "CO": "Colorado",
 "CT": "Connecticut",
 "DE": "Delaware",
 "DC": "District Of Columbia",
 "FM": "Federated States Of Micronesia",
 "FL": "Florida",
 "GA": "Georgia",
 "GU": "Guam",
 "HI": "Hawaii",
 "ID": "Idaho",
 "IL": "Illinois",
 "IN": "Indiana",
 "IA": "Iowa",
 "KS": "Kansas",
 "KY": "Kentucky",
 "LA": "Louisiana",
 "ME": "Maine",
 "MH": "Marshall Islands",
 "MD": "Maryland",
 "MA": "Massachusetts",
 "MI": "Michigan",
 "MN": "Minnesota",
 "MS": "Mississippi",
 "MO": "Missouri",
 "MT": "Montana",
 "NE": "Nebraska",
 "NV": "Nevada",
 "NH": "New Hampshire",
 "NJ": "New Jersey",
 "NM": "New Mexico",
 "NY": "New York",
 "NC": "North Carolina",
 "ND": "North Dakota",
 "MP": "Northern Mariana Islands",
 "OH": "Ohio",
 "OK": "Oklahoma",
 "OR": "Oregon",
 "PW": "Palau",
 "PA": "Pennsylvania",
 "PR": "Puerto Rico",
 "RI": "Rhode Island",
 "SC": "South Carolina",
 "SD": "South Dakota",
 "TN": "Tennessee",
 "TX": "Texas",
 "UT": "Utah",
 "VT": "Vermont",
 "VI": "Virgin Islands",
 "VA": "Virginia",
 "WA": "Washington",
 "WV": "West Virginia",
 "WI": "Wisconsin",
 "WY": "Wyoming"
};

console.log( 'The key for "Massachusetts" is "' + getKey( states, 'Massachusetts' ) + '"' );
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>


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