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


386

我有一个非常简单的JavaScript对象,用作关联数组。是否有一个简单的函数允许我获取值的键,还是必须迭代该对象并手动找到它?


没有此类标准功能可以执行此操作。如果映射是真正的双向映射,那么构造一个“翻转”映射并对其进行索引就很简单了。否则,一个简单的属性迭代器(可能具有hasOwnProperty gaurd)和隐藏在函数内的提前返回功能就可以很好地实现……

如果一个对象被多个键引用,怎么办?var o = []; var map = {first: o, second: o}。什么会find_key(o)回来?
Gareth 2012年

3
没关系;)我只打算将它用于具有唯一键值对的数组。
2012年


我制作了一个没有迭代的版本stackoverflow.com/a/36705765/696535。在jsfiddle中测试所有建议的解决方案将很有趣
Pawel

Answers:


90

使用Underscore.js库:

var hash = {
  foo: 1,
  bar: 2
};

(_.invert(hash))[1]; // => 'foo'

380
@GeorgeJempty并非每个人都希望加载5kb的库来进行简单的密钥查找;)
tckmn 2014年

4
仅供参考,供任何寻求可为您提供与值匹配的所有键的解决方案的人使用:这将不起作用。
Brett 2014年

2
下划线键也将起作用。underscorejs.org/#keys _.keys({一个:1,两个:2,3:3}); => [“一个”,“两个”,“三个”]
Thaddeus Albers 2014年

1
_.invert在默认字符串序列化冲突时包含对象的值不起作用。您可以使用以下可憎的手段:_.chain(hash).pairs().findWhere({1: 1}).value()[0]
DanHorner

3
这不是应该接受的答案,它通过一个库提出了一个解决方案,该方案强制更改当前代码结构
Matteo,

590
function getKeyByValue(object, value) {
  return Object.keys(object).find(key => object[key] === value);
}

ES6,没有原型突变或外部库。

例,

function getKeyByValue(object, value) {
  return Object.keys(object).find(key => object[key] === value);
}


const map = {"first" : "1", "second" : "2"};
console.log(getKeyByValue(map,"2"));


8
好吧,如果您不支持IE11,那就真的很干净:-)如果是这样,则需要一个
polyfill

4
根据实现的不同,这可能会占用O(n)空间,因为具体keys()化了密钥集。
David Ehrmann

2
干净但是很慢。
飞船

4
如果多个键具有相同的值使用过滤器,而不是发现function getKeyByValue(object, value) { return Object.keys(object).filter(key => object[key] === value); }
saketh

大声笑。这并不慢,因为O(n)几乎是最好的运行时。
Ben Wainwright

179

没有可用的标准方法。您需要进行迭代,然后可以创建一个简单的帮助器:

Object.prototype.getKeyByValue = function( value ) {
    for( var prop in this ) {
        if( this.hasOwnProperty( prop ) ) {
             if( this[ prop ] === value )
                 return prop;
        }
    }
}

var test = {
   key1: 42,
   key2: 'foo'
};

test.getKeyByValue( 42 );  // returns 'key1'

一个警告:即使以上方法可行,扩展任何宿主或本机对象的名称通常也是一个坏主意.prototype。我在这里这样做是因为它非常适合该问题。无论如何,您可能应该在之外使用此函数.prototype,并将对象传递给它。


2
实际上,如果您知道for-in循环在属性链中向下移动就可以了,这意味着“ for(obj中的var key)”会在某个时候为您提供“ getKeyByValue”作为“ key”。

哦,我爱这个值不存在时如何隐式返回undefined。做得好。同样,仅是一个兴趣点,它就会执行O(n),因此,如果对象具有大量属性(例如,大城市中的人们及其地址列表),则可能需要更有效的搜索。也许排序值和二进制搜索?嗯
corbin

非常感谢,到我看到一个糟糕的主意时,我想知道为什么然后搜索此内容并在此处添加此答案以进行增强和广泛阅读。stackoverflow.com/questions/3085240/...
simongcc

1
@jAndy不是===,而是==。您的代码不适用于===。返回未定义。
德克斯特(Dexter)2015年

我认为将其转换为字符串会更好地修复类型错误,只要.toString()愿意就可以添加obj[ key ].toString()和添加值...
CrandellWS 2015年

129

如前所述,需要迭代。例如,在现代浏览器中,您可能会:

var key = Object.keys(obj).filter(function(key) {return obj[key] === value})[0];

其中value包含您要查找的值。话虽如此,我可能会使用一个循环。

否则,您可以使用适当的“ hashmap”对象-JS中有多种实现-或由您自己实现。

更新2018

六年过去了,但是我仍然可以在这里投票,所以我觉得应该在答案本身而不是评论中提及一个针对现代浏览器/环境的更现代的解决方案:

const key = Object.keys(obj).find(key => obj[key] === value);

当然它也可以是一个功能:

const getKeyByValue = (obj, value) => 
        Object.keys(obj).find(key => obj[key] === value);

18
ES6:Object.keys(obj).or(o=>o[key] === value)
Benjamin Gruenbaum 2013年

不幸的是,箭头功能还不是任何“现代”浏览器,因此目前还没用–我在Firefox Nightly的jetpack中使用它,它将在Firefox 22中使用。无论如何,我不知道任何or数组的方法,在这里我不清楚它的目的:我将不胜感激!:)
ZER0

1
至于箭头,它来了,我在等待它:)可以or肯定!它是最近才被评估和接受的(我认为还没有人实现它)。它要做的是找到与谓词匹配的数组的第一个元素并返回它。所以[1,2,3,4].or(x=>x>2)会回来3[1,2,3,4,5].or(x=>x<3)也会回来1。类似于C#的FirstOrDefault :)
Benjamin Gruenbaum

是的,箭头来了,但是它将被广泛使用-除非像我一样,有人正在使用特定的引擎。我不知道有关ES6的新建议,我认为已经很封闭:您是否有关于该or方法的链接?从您提到的内容来看,它似乎返回了与谓词“或”数组本身匹配的项?
ZER0

1
如后所述,@ sg552 or被重命名。我相信现在您应该使用find
ZER0 '18

42

lodash方式https://lodash.com/docs#findKey

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

_.findKey(users, { 'age': 1, 'active': true });
// → 'pebbles'


Lodash显然是此问题的最佳解决方案。我发现,比下划线更好。
阿里克

4
仅供参考,“强调方式”:_.findKey(users, { 'age': 1, 'active': true });...相同
craigmichaelmartin

如果array是您需要使用的值:-let obj = {a:[1,2],b:[3,4],c:[5,6]} _.findKey(obj,function(val){返回_.isEqual(val,[5,6]);});
ashishyadaveee11

8
如果您的值很简单,例如字符串或整数,则与预期相反,它将不起作用。例如_.find_key({a: "A", b:"B"}, "B"})返回,undefined如此处所述您需要这样做 _.find_key({a: "A", b:"B"}, _.partial(_.isEqual,"B")})
ryan2johnson9

1
@ ryan2johnson9这就是我与洛戴丝(Lodash)的问题。我很难理解一些功能(显然我是唯一的)。但是无论如何,还是谢谢。我找到了另一个更短的解决方案。它会在较大的物体上堆放过度,因此请小心使用此物体。_.invert(haystack)[needle]
Empi

33
function extractKeyValue(obj, value) {
    return Object.keys(obj)[Object.values(obj).indexOf(value)];
}

专为闭包编译器提取键名而编译后将未知

更性感的版本,但使用了未来的Object.entries功能

function objectKeyByValue (obj, val) {
  return Object.entries(obj).find(i => i[1] === val);
}

7
我认为这是2017年以来最好的版本,因为它使用纯JavaScript。
脑袋

如果您有两个或多个具有相同值的数字,则似乎不起作用
JuicY_Burrito

@SamuelChen是正确的,但是如果它有效,则意味着需要一个数组。凡Object.entries(obj).find(i => i[1] === val);使用filter代替Object.entries(obj).filter(i => i[1] === val);
帕维尔

24

ES6 +一线

let key = Object.keys(obj).find(k=>obj[k]===value);

返回具有以下值的所有键:

let keys = Object.keys(obj).filter(k=>obj[k]===value);

1
应该是可接受的答案,因为没有依赖性。
安德鲁·舒尔茨

22

我使用此功能:

Object.prototype.getKey = function(value){
  for(var key in this){
    if(this[key] == value){
      return key;
    }
  }
  return null;
};

用法:

// ISO 639: 2-letter codes
var languageCodes = {
  DA: 'Danish',
  DE: 'German',
  DZ: 'Bhutani',
  EL: 'Greek',
  EN: 'English',
  EO: 'Esperanto',
  ES: 'Spanish'
};

var key = languageCodes.getKey('Greek');
console.log(key); // EL

10
+1整洁的解决方案。但是我有一个问题:obj.hasOwnProperty(key)在这种情况下,您不应该一直检查还是不必要?
V-Light

5
突变对象原型是一种不好的做法:stackoverflow.com/questions/23807805/…–
乔恩·库普斯

18

不可迭代的解决方案

主功能:

var keyByValue = function(value) {

    var kArray = Object.keys(greetings);        // Creating array of keys
    var vArray = Object.values(greetings);      // Creating array of values
    var vIndex = vArray.indexOf(value);         // Finding value index 

    return kArray[vIndex];                      // Returning key by value index
}

具有键和值的对象:

var greetings = {
    english   : "hello",
    ukranian  : "привіт"
};

测试:

keyByValue("привіт");
// => "ukranian"

更简单: Object.keys(greetings )[Object.values(greetings ).indexOf('привіт')]
修士

16

保持原型清洁。

function val2key(val,array){
    for (var key in array) {
        if(array[key] == val){
            return key;
        }
    }
 return false;
}

例:

var map = {"first" : 1, "second" : 2};
var key = val2key(2,map); /*returns "second"*/

15

如果你正在使用下划线Lodash库,你可以使用_.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'

13

我创建了bimap库(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

6

没有看到以下内容:

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

由于这些值是唯一的,因此应该可以将这些值添加为一组附加键。这可以通过以下快捷方式完成。

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"

这确实假定键和值之间没有公共元素。


浏览所有解决方案时,我选择了这一解决方案。非常直观。
nehem

1
唯一不需要迭代的解决方案之一(在解决方案本身,标准库或其他库中)。
Scott Rudiger

OP确实说过,键/值对都是唯一的,因此这个低技术含量的答案真是太棒了!干得好;)
customcommander

4

鉴于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 '16

除非内存是一个约束,并且您愿意花费大量处理能力多次遍历对象,否则只需将上述“输出”保存到变量中,然后在其中查找结果即可output['x']。那是你在问什么吗?
Fabio Beltramini

2

http://jsfiddle.net/rTazZ/2/

var a = new Array(); 
    a.push({"1": "apple", "2": "banana"}); 
    a.push({"3": "coconut", "4": "mango"});

    GetIndexByValue(a, "coconut");

    function GetIndexByValue(arrayName, value) {  
    var keyName = "";
    var index = -1;
    for (var i = 0; i < arrayName.length; i++) { 
       var obj = arrayName[i]; 
            for (var key in obj) {          
                if (obj[key] == value) { 
                    keyName = key; 
                    index = i;
                } 
            } 
        }
        //console.log(index); 
        return index;
    } 

@ Fr0zenFyr:下面的链接能回答你更好的问题- stackoverflow.com/questions/8423493/...
ATUR

2

或者,更容易-用您想要的顺序使用键和值创建一个新对象,然后针对该对象进行查找。使用上面的原型代码,我们遇到了冲突。您不必在键周围使用String函数,这是可选的。

 newLookUpObj = {};
 $.each(oldLookUpObj,function(key,value){
        newLookUpObj[value] = String(key);
    });

2

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

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

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


2

好像这个问题没有被打败...

这只是一种好奇心,它带给您...

如果您确定您的对象只有字符串值,那么您真的会费劲自己来构想此实现:

var o = { a: '_A', b: '_B', c: '_C' }
  , json = JSON.stringify(o)
  , split = json.split('')
  , nosj = split.reverse()
  , o2 = nosj.join('');

var reversed = o2.replace(/[{}]+/g, function ($1) { return ({ '{':'}', '}':'{' })[$1]; })
  , object = JSON.parse(reversed)
  , value = '_B'
  , eulav = value.split('').reverse().join('');

console.log('>>', object[eulav]);

也许有一些有用的东西可以在这里建立...

希望这使您开心。


2

这是Lodash的解决方案,它适用于平面键=>值对象,而不是嵌套对象。接受的答案建议使用_.findKey适用于带有嵌套对象的对象,但在这种常见情况下不起作用。

此方法反转对象,将键交换为值,然后通过在新的(反转的)对象上查找值来查找键。如果找不到该键,则false返回该键,我更愿意这样做undefined,但是您可以在中_.get方法的第三个参数中轻松地将其换出getKey()

// 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>


2

这是我的解决方案首先:

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

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),这两个参数是对象和要查找的键的值。因此,此方法是可重用的,并且您不需要每次仅通过为此函数传递两个参数来手动迭代对象。


2

ES6方法:

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

0

我通常推荐lodash而不是下划线。

如果有,请使用它。

如果不这样做,则应考虑使用lodash.invert npm软件包,该软件包很小。

这是您可以使用gulp测试的方法:

1)创建一个名为gulpfile.js的文件,其内容如下:

// Filename: gulpfile.js
var gulp = require('gulp');
var invert = require('lodash.invert');   
gulp.task('test-invert', function () {
  var hash = {
    foo: 1,
    bar: 2
  };
  var val = 1;
  var key = (invert(hash))[val];  // << Here's where we call invert!
  console.log('key for val(' + val + '):', key);
});

2)安装lodash.invert软件包和gulp

$ npm i --save lodash.invert && npm install gulp

3)测试是否有效:

$ gulp test-invert
[17:17:23] Using gulpfile ~/dev/npm/lodash-invert/gulpfile.js
[17:17:23] Starting 'test-invert'...
key for val(1): foo
[17:17:23] Finished 'test-invert' after 511 μs

参考文献

https://www.npmjs.com/package/lodash.invert

https://lodash.com/

lodash和下划线之间的区别

https://github.com/gulpjs/gulp


为什么Gulp参与其中?只需运行脚本…
Ry-

0

下划线js解决方案

let samplLst = [{id:1,title:Lorem},{id:2,title:Ipsum}]
let sampleKey = _.findLastIndex(samplLst,{_id:2});
//result would be 1
console.log(samplLst[sampleKey])
//output - {id:2,title:Ipsum}

0

这为我工作,以获得对象的键/值。

let obj = {
        'key1': 'value1',
        'key2': 'value2',
        'key3': 'value3',
        'key4': 'value4'
    }
    Object.keys(obj).map(function(k){ 
    console.log("key with value: "+k +" = "+obj[k])    
    
    })
    


-1

真的很简单。

const CryptoEnum = Object.freeze({
                    "Bitcoin": 0, "Ethereum": 1, 
                    "Filecoin": 2, "Monero": 3, 
                    "EOS": 4, "Cardano": 5, 
                    "NEO": 6, "Dash": 7, 
                    "Zcash": 8, "Decred": 9 
                  });

Object.entries(CryptoEnum)[0][0]
// output => "Bitcoin"

6
无法保证对象顺序将相同...
Downgoat

-2

把事情简单化!

您无需通过复杂的方法或库来过滤对象,Javascript具有一个称为Object.values的内置函数。

例:

let myObj = {jhon: {age: 20, job: 'Developer'}, marie: {age: 20, job: 
'Developer'}};

function giveMeTheObjectData(object, property) {
   return Object.values(object[property]);
}

giveMeTheObjectData(myObj, 'marie'); // => returns marie: {}

这将返回对象属性数据。

参考文献

https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Object/values

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.