Как получить ключ в объекте JavaScript по его значению?


388

У меня есть довольно простой объект JavaScript, который я использую в качестве ассоциативного массива. Существует ли простая функция, позволяющая мне получить ключ для значения, или мне нужно выполнить итерацию объекта и найти его вручную?


Для этого нет такой стандартной функции. Если отображение действительно двунаправленное, то тривиально построить «перевернутую» карту и проиндексировать ее. В противном случае простой итератор свойства (возможно, с помощью hasOwnProperty gaurd) и ранний возврат, скрытый внутри функции, прекрасно

Как это может работать, если на объект ссылается более одного ключа? var o = []; var map = {first: o, second: o}, Что бы find_key(o)вернуться?
Гарет

3
не имеет значения;) Я намеревался использовать его только для массива с уникальными парами ключ-значение.
Арик


Я сделал версию без итерации stackoverflow.com/a/36705765/696535 . Было бы интересно протестировать все предложенные решения в jsfiddle
Pawel

Ответы:


90

С библиотекой Underscore.js :

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

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

387
@GeorgeJempty Не каждый хочет загрузить библиотеку 5 КБ для простого поиска ключа;)
tckmn

4
Просто к сведению тех, кто ищет решение, которое даст вам ВСЕ ключи, соответствующие значению: это не сработает.
Бретт

2
клавиши подчеркивания тоже подойдут. underscorejs.org/#keys _.keys ({один: 1, два: 2, три: 3}); => ["one", "two", "three"]
Таддеус Альберс

1
_.invert не работает, когда значения включают объекты, так как сериализация строк по умолчанию сталкивается. Вы можете использовать эту мерзость:_.chain(hash).pairs().findWhere({1: 1}).value()[0]
DanHorner

3
Это не должен быть принятый ответ, он предлагает решение через библиотеку, которое вызывает изменение в текущей структуре кода
Matteo

594
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
Chexpir

4
В зависимости от реализации, это, вероятно, занимает место O (n), поскольку keys()материализует набор ключей.
Дэвид Эрманн

2
Чисто, но медленно.
Дирижабль

4
Если несколько ключей имеют одинаковое значение, используйте фильтр вместо findfunction getKeyByValue(object, value) { return Object.keys(object).filter(key => object[key] === value); }
saketh

Лол. Это не медленно, это O (n), что в значительной степени наилучшее время выполнения.
Бен Уэйнрайт

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 (var key in obj) даст вам getKeyByValue в качестве «key» в какой-то момент.

О, боже, мне нравится, как это скрытно возвращает неопределенное значение, если значение не существует. Отлично сработано. Кроме того, просто интересный момент, это будет выполнять O (n), поэтому, если объект имеет массу свойств (например, список людей в большом городе и их адреса), вы, вероятно, захотите более эффективный поиск. Может быть, сортировка значений и бинарный поиск? А?
Корбин

Большое спасибо, к тому времени, когда я увидел плохую идею, я удивляюсь, почему тогда я искал это и добавил сюда для улучшения ответа и обширного чтения. stackoverflow.com/questions/3085240/…
simongcc

1
@jAndy это не ===, это ==. Ваш код не работает с ===. Возвращает неопределенное.
Декстер

Я думаю, что преобразование в строку было бы лучше, чтобы исправить ошибки типа, просто добавьте .toString()like obj[ key ].toString()и к значению, если это необходимо ...
CrandellWS

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)
Бенджамин Грюнбаум

К сожалению, функция «стрелка» еще не является «современным» браузером, поэтому в данный момент она немного бесполезна - я использую ее в Jetpack на Firefox Nightly, она будет в 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 #'s FirstOrDefault :)
Бенджамин Грюнбаум

Да, стрелка идет, но она будет широко использоваться - если, как и я, кто-то работает над конкретным движком. Я не знал о новом предложении для ES6, я думал, что это было довольно закрыто: у вас есть ссылка о orметоде? Из того, что вы упомянули, кажется, что он возвращает элемент, который соответствует предикату "или" сам массив?
ZER0

1
@ sg552, как упоминалось позже, orбыл переименован. Я считаю, что теперь вы должны использовать найти .
ZER0

42

Лодаш путь 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

если массив - это значение, которое вы должны использовать: - let obj = {a: [1, 2], b: [3, 4], c: [5, 6]} _.findKey (obj, function (val) { return _.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 Это моя проблема с Лодашем. Мне трудно понять некоторые функции (видимо, я единственный). Но все равно спасибо, это работает. Я нашел другое, более короткое решение. Это приводит к перегрузке больших объектов, поэтому будьте осторожны с этим. _.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);
Павел

Используйте разрушение, чтобы сделать его еще лучшеObject.entries(obj).find( ([ key, value ]) => value === val);
hitautodestruct

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('привіт')]
shutsman

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

Если вы работаете с библиотекой Underscore или 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"

Поиск соответствия ключ-значение одинаково быстр в обоих направлениях. Под капотом нет дорогостоящих обходов объектов / массивов, поэтому среднее время доступа остается постоянным независимо от размера данных.


Одно из единственных решений, которое не требует итерации (ни в самом решении, ни в стандартной библиотеке, ни в другой библиотеке).
Скотт Рудигер

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"

Это предполагает, что между ключами и значениями нет общих элементов.


Просматривая все решения, я пошел с этим. Очень интуитивно понятно
Нехем

1
Одно из единственных решений, которое не требует итерации (ни в самом решении, ни в стандартной библиотеке, ни в другой библиотеке).
Скотт Рудигер

Оператор сказал, что все пары ключ / значение были уникальны, поэтому этот низкотехнологичный ответ просто фантастический! Молодцы;)
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

Если память не является ограничением, и вы готовы потратить много вычислительной мощности, чтобы просмотреть объект много раз, просто сохраните «выходные данные», как указано выше, в переменную и посмотрите результат там… как output['x']. Это то, что вы спрашивали?
Фабио Бельтрамини

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 (массив, значение), который принимает два параметра, которые являются объектом и значением ключа, который вы ищете. Таким образом, этот метод можно использовать повторно, и вам не нужно каждый раз вручную повторять объект, передавая только два параметра для этой функции.


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 и проглотите

$ 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


Почему Гулп участвует здесь? Просто запустите сценарий ...
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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.