Como obter uma chave em um objeto JavaScript por seu valor?


387

Eu tenho um objeto JavaScript bastante simples, que eu uso como uma matriz associativa. Existe uma função simples que me permita obter a chave de um valor ou preciso iterar o objeto e descobri-lo manualmente?


Não existe uma função padrão para fazer isso. Se o mapeamento for realmente bidirecional, será trivial construir um mapa "invertido" e indexá-lo. Caso contrário, uma propriedade de iteração simples (com um gaurd hasOwnProperty, talvez) e um início de retorno escondida dentro de uma função faz apenas bem ...

Como isso funcionaria se um objeto fosse referenciado por mais de uma chave? var o = []; var map = {first: o, second: o}. O que find_key(o)retornaria?
Gareth

3
não importa;) Eu pretendia usá-lo apenas para uma matriz com pares de valores-chave exclusivos.
Arik #


Eu fiz uma versão sem iteração stackoverflow.com/a/36705765/696535 . Seria interessante para testar todas as soluções propostas no jsFiddle
Pawel

Respostas:


90

Com a biblioteca Underscore.js :

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

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

385
@GeorgeJempty Nem todo mundo quer carregar uma biblioteca 5kb para uma pesquisa de chave simples;)
tckmn

4
Apenas para sua informação, para quem procura uma solução que obtenha TODAS as chaves que correspondem a um valor: isso não funcionará.
Brett

2
as teclas de sublinhado também funcionarão. underscorejs.org/#keys _.keys ({um: 1, dois: 2, três: 3}); => ["um", "dois", "três"] #
Thaddeus Albers 15/05

11
_.invert não funciona onde os valores incluem objetos quando a serialização de string padrão colide. Você pode usar esta abominação:_.chain(hash).pairs().findWhere({1: 1}).value()[0]
DanHorner 9/15

3
Esta não deve ser a resposta aceito, ele propor uma solução através de uma biblioteca que força uma mudança na estrutura de código atual
Matteo

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

ES6, sem mutações de protótipo ou bibliotecas externas.

Exemplo,

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
Bem, realmente limpo, se você não apoiar IE11 :-) Se assim for, você precisa de um polyfill
Chexpir

4
Dependendo da implementação, isso provavelmente ocupa O (n) espaço, pois keys()materializa o conjunto de chaves.
David Ehrmann

2
Limpo, mas lento.
Dirigível

4
Se as chaves múltiplas têm filtro de uso valor Same, em vez de descobertafunction getKeyByValue(object, value) { return Object.keys(object).filter(key => object[key] === value); }
saketh

Ri muito. Isso não é lento, é O (n) que é praticamente o melhor tempo de execução possível.
Ben Wainwright

179

Nenhum método padrão disponível. Você precisa iterar e pode criar um auxiliar simples:

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'

Uma palavra de cautela : Mesmo que as opções acima funcionem, geralmente é uma má idéia estender qualquer host ou objeto nativo .prototype. Fiz aqui porque se encaixa muito bem no problema. De qualquer forma, você provavelmente deve usar essa função fora do .prototypee passar o objeto para ele.


2
Na verdade, tudo bem se você souber coisas desse tipo, o loop for-in desce a cadeia de propriedades, o que significa que "for (var key in obj)" daria a você "getKeyByValue" como "key" em algum momento.

Oh cara, eu amo como isso furtivamente retorna indefinido se o valor não existe. Bem feito. Além disso, apenas um ponto de interesse, isso executaria O (n); portanto, se o objeto tivesse várias propriedades (como uma lista de pessoas em uma cidade grande e seus endereços), você provavelmente desejaria uma pesquisa mais eficiente. Talvez classificar valores e pesquisa binária? Eh?
Corbin

Muito obrigado, quando vi uma má ideia, pergunto-me por que, então, pesquisei isso e adicionei aqui esse aprimoramento de resposta e uma leitura extensiva. stackoverflow.com/questions/3085240/…
simongcc

11
@jAndy NÃO é ===, é ==. Seu código não funciona com ===. Retorna indefinido.
Dexter

Eu acho que convertê-lo em uma string seria melhor para corrigir erros de tipo, basta adicionar .toString()como obj[ key ].toString()e ao valor, se desejado ...
CrandellWS

129

Como dito, a iteração é necessária. Por exemplo, no navegador moderno, você pode ter:

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

Onde valuecontém o valor que você está procurando. Disse que eu provavelmente usaria um loop.

Caso contrário, você poderá usar um objeto "hashmap" adequado - existem várias implementações no JS ao redor - ou implementar por conta própria.

ATUALIZAÇÃO 2018

Seis anos se passaram, mas ainda recebo voto aqui, então sinto que uma solução mais moderna - para navegador / ambiente moderno - deve ser mencionada na resposta em si e não apenas nos comentários:

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

Claro que também pode ser uma função:

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

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

Infelizmente a função de seta não é qualquer browser "moderno", no entanto, por isso é um pouco inútil no momento - Eu estou usando-o em jetpack no Firefox Nightly, será no Firefox 22. De qualquer forma, eu não estou ciente sobre qualquer orda matriz método, e não está claro para mim seu objetivo aqui: vou apreciar alguns detalhes adicionais! :)
ZER0

11
Quanto à flecha, ela está chegando e eu estou esperando por ela :) Com orcerteza! Foi avaliado e aceito apenas recentemente (acho que ninguém o implementa ainda). O que ele faz é encontrar o primeiro elemento de uma matriz correspondente a um predicado e retorná-lo. Então [1,2,3,4].or(x=>x>2)voltaria 3e [1,2,3,4,5].or(x=>x<3)voltaria 1. Algo como FirstOrDefault C # 's :)
Benjamin Gruenbaum

Sim, a flecha está chegando, mas será preciso ser usada amplamente - a menos que, como eu, alguém esteja trabalhando em um mecanismo específico. Eu não estava ciente da nova proposta para o ES6, pensei que estava bem fechada: você tem um link sobre o ormétodo? Pelo que você mencionou, parece que ele retorna o item que corresponde ao predicado "ou" a própria matriz?
ZER0

11
@ sg552, como foi mencionado mais tarde, orfoi renomeado. Eu acredito que agora você deve usar o find .
ZER0

42

A maneira 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 é claramente a melhor solução para esse problema. Melhor ainda, acho, do que o caminho sublinhado.
Arik #

4
FYI, "o caminho sublinhado": _.findKey(users, { 'age': 1, 'active': true });... é o mesmo
craigmichaelmartin

se matriz for o valor que você precisa usar: - deixe obj = {a: [1, 2], b: [3, 4], c: [5, 6]} _.findKey (obj, function (val) { return _.isEqual (val, [5, 6]);});
ashishyadaveee11

8
se seus valores forem simples, como seqüências de caracteres ou números inteiros, ao contrário da expectativa, isso não funcionará. por exemplo, _.find_key({a: "A", b:"B"}, "B"})retornos undefinedconforme indicado aqui que você precisa fazer _.find_key({a: "A", b:"B"}, _.partial(_.isEqual,"B")})
ryan2johnson9

11
@ ryan2johnson9 Esse é o meu problema com o Lodash. Estou tendo dificuldade para entender algumas funções (aparentemente eu sou a única). Mas obrigado de qualquer maneira, funciona. Encontrei outra solução mais curta. Isso causa excesso de objetos maiores, portanto, tenha cuidado com este. _.invert(haystack)[needle]
Emp3

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

Feito para o compilador de fechamento para extrair o nome da chave que será desconhecido após a compilação

Versão mais sexy, mas usando a Object.entriesfunção futura

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

7
Acho que este é o melhor para 2017 ou mais, pois usa JavaScript simples.
brainbag

Não parece trabalho, se você tiver dois ou mais números que têm o mesmo valor
JuicY_Burrito

@SamuelChen isso mesmo, mas se funcionasse, significa que uma matriz é necessária como resultado. Onde Object.entries(obj).find(i => i[1] === val);usar em filtervez dissoObject.entries(obj).filter(i => i[1] === val);
Pawel

Use a desestruturação para torná-la ainda melhorObject.entries(obj).find( ([ key, value ]) => value === val);
hitautodestruct

24

ES6 + One Liners

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

Retorne todas as chaves com o valor:

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

11
Deve ser a resposta aceita, pois não há dependências.
Andrew Schultz

22

Eu uso esta função:

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

Uso:

// 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 solução pura. Mas eu tenho uma pergunta: você não deve sempre procurar obj.hasOwnProperty(key)ou é desnecessário neste caso?
V-luz

5
Mutando o protótipo de objeto é uma prática ruim: stackoverflow.com/questions/23807805/...
Jon Koops

18

Solução não iterável

Função principal:

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
}

Objeto com chaves e valores:

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

Teste:

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

mais simples: Object.keys(greetings )[Object.values(greetings ).indexOf('привіт')]
shutsman 7/10/19

16

Mantenha seu protótipo limpo.

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

Exemplo:

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

15

Se você estiver trabalhando com a biblioteca Underscore ou Lodash , poderá usar a função _.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

Criei a biblioteca bimap ( https://github.com/alethes/bimap ) que implementa uma interface de mapa bidirecional JavaScript poderosa, flexível e eficiente. Ele não possui dependências e é utilizável no servidor (no Node.js, você pode instalá-lo npm install bimap) e no navegador (vinculando-se a lib / bimap.js ).

As operações básicas são realmente simples:

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"

A recuperação do mapeamento de valores-chave é igualmente rápida nas duas direções. Não há travessias caras de objetos / matrizes sob o capô, portanto o tempo médio de acesso permanece constante, independentemente do tamanho dos dados.


Uma das únicas soluções que não requerem iteração (na própria solução, na biblioteca padrão ou em outra biblioteca).
Scott Rudiger

6

não viu o seguinte:

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

Como os valores são únicos, deve ser possível adicionar os valores como um conjunto adicional de chaves. Isso pode ser feito com o seguinte atalho.

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

Isso permitiria a recuperação por meio da chave ou do valor:

var key = "apple";
var value = "an apple";

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

Isso pressupõe que não há elementos comuns entre as chaves e os valores.


Procurando todas as soluções, eu fui com esta. Muito intuitivo.
Nehem

11
Uma das únicas soluções que não requerem iteração (na própria solução, na biblioteca padrão ou em outra biblioteca).
Scott Rudiger

O OP disse que os pares chave / valor eram todos únicos, portanto, essa resposta de baixa tecnologia é simplesmente fantástica! Bem feito;)
customcommander 22/01

4

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

  • Para usar o primeiro valor (por exemplo 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)

  • Para usar o último valor (por exemplo 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)

  • Para obter uma matriz de chaves para cada valor (por exemplo 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)


11
esta é definitivamente a melhor resposta, mas eu estava coçando a cabeça sobre uma maneira de transformá-la para retornar apenas a chave de um determinado objeto, ou seja, ser funcionalmente equivalente ao indexOf de uma matriz.
Souhaieb Besbes

A menos que a memória seja uma restrição e você esteja disposto a gastar muito poder de processamento para examinar o objeto várias vezes, salve a "saída", conforme indicado acima, em uma variável e procure o resultado lá ... como output['x']. Era isso que você estava perguntando?
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: O link a seguir pode responder melhor a suas perguntas - stackoverflow.com/questions/8423493/…
Atur

2

Ou, mais fácil ainda - crie um novo objeto com as chaves e os valores na ordem que você deseja e, em seguida, procure esse objeto. Tivemos conflitos usando os códigos de protótipo acima. Você não precisa usar a função String ao redor da tecla, isso é opcional.

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


2

Como se essa pergunta não tivesse sido derrotada ...

Aqui está um apenas para qualquer curiosidade que isso traz a você ...

Se você tem certeza de que seu objeto terá apenas valores de sequência, você pode realmente se cansar de conjurar esta implementação:

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]);

Talvez haja algo útil para construir daqui ...

Espero que isso diverte você.


2

Aqui está uma solução Lodash para isso que funciona para o objeto chave => value, em vez de um objeto aninhado. A sugestão da resposta aceita de usar_.findKey funciona para objetos com objetos aninhados, mas não funciona nessa circunstância comum.

Essa abordagem inverte o objeto, trocando chaves por valores e, em seguida, localiza a chave pesquisando o valor no novo objeto (invertido). Se a chave não for encontrada, falseserá retornada, o que eu prefiro undefined, mas você pode facilmente trocá-la no terceiro parâmetro do_.get método 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

Aqui está a minha solução primeiro:

Por exemplo, suponho que tenhamos um objeto que contenha três pares de valores:

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

Podemos simplesmente escrever uma findKey (matriz, valor) que aceita dois parâmetros que são um objeto e o valor da chave que você está procurando. Como tal, esse método é reutilizável e você não precisa iterar manualmente o objeto todas as vezes passando apenas dois parâmetros para esta função.


2

Métodos ES6 :

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

0

Eu normalmente recomendo lodash em vez de sublinhado.

Se você tiver, use-o.

Caso contrário, considere usar o pacote lodash.invert npm, que é bem pequeno.

Veja como você pode testá-lo usando gulp:

1) Crie um arquivo chamado gulpfile.js com o seguinte conteúdo:

// 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) Instale o pacote lodash.invert e gulp

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

3) Teste se funciona:

$ 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

Referências

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

https://lodash.com/

Diferenças entre lodash e sublinhado

https://github.com/gulpjs/gulp


Por que Gulp está envolvido aqui? Basta executar o script…
Ry-

0

Sublinhar a solução 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

isso funcionou para eu obter a chave / valor do objeto.

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

Realmente simples.

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
Não há garantia de que o objeto pedido será o mesmo ...
Downgoat

-2

Mantenha simples!

Você não precisa filtrar o objeto por métodos ou bibliotecas sofisticados, o Javascript possui uma função integrada chamada Object.values .

Exemplo:

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: {}

Isso retornará os dados da propriedade do objeto.

Referências

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.