¿Cómo obtener una clave en un objeto JavaScript por su valor?


387

Tengo un objeto JavaScript bastante simple, que uso como una matriz asociativa. ¿Existe una función simple que me permita obtener la clave para un valor, o tengo que iterar el objeto y encontrarlo manualmente?


No existe tal función estándar para hacer esto. Si el mapeo es verdaderamente bidireccional, entonces es trivial construir un mapa "invertido" e indexarlo. De lo contrario, una simple propiedad-iterador (con un guardia de hasOwnProperty, tal vez) y un temprano retorno escondido dentro de una función hace precisamente muy bien ...

¿Cómo podría funcionar esto si un objeto fuera referenciado por más de una clave? var o = []; var map = {first: o, second: o}. ¿Qué find_key(o)volvería?
Gareth

3
no importa;) Solo pretendía usarlo para una matriz con pares clave-valor únicos.
arik


He hecho una versión sin iteración stackoverflow.com/a/36705765/696535 . Sería interesante probar todas las soluciones propuestas en jsfiddle
Pawel

Respuestas:


90

Con la biblioteca Underscore.js :

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

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

385
@GeorgeJempty No todos quieren cargar una biblioteca de 5kb para una simple búsqueda de claves;)
tckmn

44
Solo para tu información, para cualquiera que busque una solución que obtenga TODAS las claves que coincidan con un valor: esto no funcionará.
Brett

2
las teclas de subrayado también funcionarán. underscorejs.org/#keys _.keys ({uno: 1, dos: 2, tres: 3}); => ["uno", "dos", "tres"]
Thaddeus Albers

1
_.invert no funciona donde los valores incluyen objetos, ya que la serialización de cadenas predeterminada colisiona. Puede usar esta abominación:_.chain(hash).pairs().findWhere({1: 1}).value()[0]
DanHorner

3
Esto no debería ser la respuesta aceptada, se propone una solución a través de una biblioteca que fuerza un cambio en la estructura del código actual
Matteo

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

ES6, sin mutaciones prototipo o bibliotecas externas.

Ejemplo,

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
Bueno, realmente limpio si no soportas IE11 :-) Si es así, necesitas un polyfill
Chexpir

44
Dependiendo de la implementación, esto probablemente ocupa espacio O (n) ya que keys()materializa el conjunto de claves.
David Ehrmann

2
Limpio pero lento.
Dirigible el

44
Si las claves múltiples tienen uso de filtro de valor mismo lugar de hallazgofunction getKeyByValue(object, value) { return Object.keys(object).filter(key => object[key] === value); }
saketh

Jajaja Esto no es lento, es O (n), que es prácticamente el mejor tiempo de ejecución posible.
Ben Wainwright

179

No hay un método estándar disponible. Necesita iterar y puede crear un ayudante simple:

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'

Una advertencia : incluso si lo anterior funciona, generalmente es una mala idea extender cualquier host u objeto nativo .prototype. Lo hice aquí porque encaja muy bien con el problema. De todos modos, probablemente debería usar esta función fuera del .prototypey pasar el objeto en su lugar.


2
En realidad está bien si sabes cosas así, el bucle for-in baja por la cadena de propiedades, lo que significa que "for (var key in obj)" te daría "getKeyByValue" como "key" en algún momento.

Oh hombre, me encanta cómo esto vuelve sigilosamente indefinido si el valor no existe. Bien hecho. Además, solo un punto de interés, esto llevaría a cabo O (n), por lo que si el objeto tuviera una tonelada de propiedades (como una lista de personas en una gran ciudad y sus direcciones), probablemente querría una búsqueda más eficiente. ¿Quizás ordenar valores y búsqueda binaria? Eh?
corbin

Muchas gracias, cuando vi una mala idea, me pregunto por qué busqué a través de esto y agregué aquí para esta mejora de respuesta y lectura extensa. stackoverflow.com/questions/3085240/…
simongcc

1
@jAndy NO es ===, es ==. Su código no funciona con ===. Vuelve indefinido.
Dexter

Creo que convertirlo en una cadena sería mejor para corregir los errores de tipo simplemente agregue me .toString()gusta obj[ key ].toString()y al valor si lo desea ...
CrandellWS

129

Como se dijo, se necesita iteración. Por ejemplo, en el navegador moderno podría tener:

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

Donde valuecontiene el valor que estás buscando. Dicho eso, probablemente usaría un bucle.

De lo contrario, podría usar un objeto "hashmap" adecuado (hay varias implementaciones en JS) o implementarlo usted mismo.

ACTUALIZACIÓN 2018

Pasaron seis años, pero todavía obtengo algo de voto aquí, así que siento que una solución más moderna, para el navegador / entorno moderno, debería mencionarse en la respuesta en sí y no solo en los comentarios:

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

Por supuesto, también puede ser una función:

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

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

Desafortunadamente, la función de flecha todavía no es un navegador "moderno", por lo que es un poco inútil en este momento: la estoy usando en jetpack en Firefox Nightly, estará en Firefox 22. De todos modos, no estoy al tanto de ninguna ormatriz método, y no está claro para mí su propósito aquí: ¡apreciaré algunos detalles adicionales! :)
ZER0

1
En cuanto a la flecha, viene y la estoy esperando :) or¡Seguro! Fue evaluado y aceptado recientemente (no creo que nadie lo implemente todavía). Lo que hace es encontrar el primer elemento de una matriz que coincida con un predicado y devolverlo. Entonces [1,2,3,4].or(x=>x>2)volvería 3y [1,2,3,4,5].or(x=>x<3)volvería 1. Algo así como FirstOrDefault de C # :)
Benjamin Gruenbaum

Sí, la flecha se acerca, pero será necesario usarla ampliamente, a menos que, como yo, alguien esté trabajando en un motor específico. No estaba al tanto de la nueva propuesta para ES6, pensé que estaba bastante cerrada: ¿tiene un enlace sobre el ormétodo? Por lo que mencionó, ¿parece que devuelve el elemento que coincide con el predicado "o" la matriz misma?
ZER0

1
@ sg552 como se mencionó más tarde, orse cambió el nombre. Creo que ahora deberías usar find .
ZER0

42

La forma 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 es claramente la mejor solución para este problema. Mejor incluso, me parece, que la forma de subrayado.
arik

44
Para su información, "la forma de subrayado": _.findKey(users, { 'age': 1, 'active': true });... es lo mismo
craigmichaelmartin

si array es el valor que necesita usar: - let obj = {a: [1, 2], b: [3, 4], c: [5, 6]} _.findKey (obj, function (val) { return _.isEqual (val, [5, 6]);});
ashishyadaveee11

8
Si sus valores son simples, como cadenas o enteros, entonces, al contrario de lo esperado, esto no funcionará. Por ejemplo, _.find_key({a: "A", b:"B"}, "B"})vuelve, undefinedcomo se indica aquí , debe hacerlo _.find_key({a: "A", b:"B"}, _.partial(_.isEqual,"B")})
ryan2johnson9

1
@ ryan2johnson9 Ese es mi problema con Lodash. Me está costando entender algunas funciones (aparentemente soy el único). Pero gracias de todos modos, funciona. Encontré otra solución más corta. Causa un exceso en los objetos más grandes, así que ten cuidado con este. _.invert(haystack)[needle]
Empi

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

Hecho para el compilador de cierre para extraer el nombre clave que será desconocido después de la compilación

Versión más sexy pero con Object.entriesfunción futura

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

77
Creo que este es el mejor para 2017+ ya que usa JavaScript simple.
brainbag

No parece funcionar si tiene dos o más números que tienen el mismo valor
JuicY_Burrito

@SamuelChen es cierto, pero si funcionó significaría que se necesita una matriz como resultado. Donde Object.entries(obj).find(i => i[1] === val);usar filteren su lugarObject.entries(obj).filter(i => i[1] === val);
Pawel

Usa la desestructuración para hacerlo aún mejorObject.entries(obj).find( ([ key, value ]) => value === val);
hitautodestruct

24

ES6 + One Liners

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

Devuelve todas las claves con el valor:

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

1
Debe ser la respuesta aceptada ya que no hay dependencias.
Andrew Schultz

22

Yo uso esta función:

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 solución ordenada. Pero tengo una pregunta: ¿no debería verificar siempre obj.hasOwnProperty(key)o es innecesario en este caso?
V-Light

55
Mutar el prototipo de objeto es una mala práctica: stackoverflow.com/questions/23807805/…
Jon Koops

18

Solución no iterable

Función 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 con claves y valores:

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

Prueba:

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

más simple: Object.keys(greetings )[Object.values(greetings ).indexOf('привіт')]
shutsman

16

Mantenga su prototipo limpio.

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

Ejemplo:

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

15

Si está trabajando con la biblioteca Underscore o Lodash , puede usar la función _.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

He creado el BIMAP biblioteca ( https://github.com/alethes/bimap ) que implementa un potente, flexible y eficiente interfaz del mapa bidireccional JavaScript. No tiene dependencias y se puede usar tanto en el lado del servidor (en Node.js, puede instalarlo con npm install bimap) como en el navegador (al vincular a lib / bimap.js ).

Las operaciones básicas son 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"

La recuperación del mapeo clave-valor es igualmente rápida en ambas direcciones. No hay recorridos costosos de objetos / conjuntos debajo del capó, por lo que el tiempo de acceso promedio permanece constante independientemente del tamaño de los datos.


Una de las únicas soluciones que no requiere iteración (ya sea en la solución en sí, la biblioteca estándar u otra biblioteca).
Scott Rudiger

6

no vi lo siguiente:

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 los valores son únicos, debería ser posible agregar los valores como un conjunto adicional de claves. Esto podría hacerse con el siguiente acceso directo.

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

Esto permitiría la recuperación a través de la clave o el valor:

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

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

Esto supone que no hay elementos comunes entre las claves y los valores.


Buscando todas las soluciones, fui con esta. Muy intuitivo
nehem

1
Una de las únicas soluciones que no requiere iteración (ya sea en la solución en sí, la biblioteca estándar u otra biblioteca).
Scott Rudiger

El OP dijo que los pares clave / valor eran todos únicos, por lo tanto, ¡esta respuesta de baja tecnología es simplemente fantástica! Bien hecho;)
customcommander

4

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

  • Para usar el primer valor (por ejemplo 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 el último valor (por ejemplo 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 obtener una matriz de claves para cada valor (por ejemplo 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
Esta es definitivamente la mejor respuesta, pero estaba rascando mi cabeza sobre una forma de transformarla para devolver solo la clave de un objeto dado, es decir, ser funcionalmente equivalente a indexOf para una matriz.
Souhaieb Besbes

A menos que la memoria sea una restricción y esté dispuesto a gastar una gran cantidad de poder de procesamiento para revisar el objeto muchas veces, simplemente guarde la "salida" como se indicó anteriormente en una variable y busque el resultado allí ... como output['x']. ¿Es eso lo que preguntabas?
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: El siguiente enlace puede responder mejor a su pregunta - stackoverflow.com/questions/8423493/…
Atur

2

O, aún más fácil: cree un nuevo objeto con las claves y los valores en el orden que desee y luego busque ese objeto. Hemos tenido conflictos al usar los códigos prototipo anteriores. No tiene que usar la función String alrededor de la tecla, eso es opcional.

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

2

Esta es una pequeña extensión del método Underscorejs, y utiliza Lodash en su lugar:

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

FindKey buscará y devolverá la primera clave que coincida con el valor.
Si desea la última coincidencia, use FindLastKey en su lugar.


2

Como si esta pregunta no hubiera sido superada ...

Aquí hay uno para cualquier curiosidad que te traiga ...

Si está seguro de que su objeto solo tendrá valores de cadena, realmente podría agotarse para evocar esta implementación:

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

Tal vez hay algo útil para construir desde aquí ...

Espero que esto te divierta.


2

Aquí hay una solución de Lodash para esto que funciona para la clave plana => objeto de valor, en lugar de un objeto anidado. La sugerencia de la respuesta aceptada de usar _.findKeyfunciona para objetos con objetos anidados, pero no funciona en esta circunstancia común.

Este enfoque invierte el objeto, intercambiando claves por valores, y luego encuentra la clave buscando el valor en el nuevo objeto (invertido). Si no se encuentra la clave, falsese devuelve, lo cual prefiero undefined, pero podría cambiarlo fácilmente en el tercer parámetro del _.getmé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

Aquí está mi solución primero:

Por ejemplo, supongo que tenemos un objeto que contiene tres 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

Simplemente podemos escribir una FindKey (matriz, valor) que toma dos parámetros que son un objeto y el valor de la clave que está buscando. Como tal, este método es reutilizable y no necesita iterar manualmente el objeto cada vez pasando solo dos parámetros para esta función.


2

Métodos ES6 :

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

0

Normalmente recomiendo lodash en lugar de subrayar.

Si lo tienes, úsalo.

Si no lo hace, debería considerar usar el paquete lodash.invert npm, que es bastante pequeño.

Así es como puedes probarlo con trago:

1) Cree un archivo llamado gulpfile.js con el siguiente contenido:

// 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 el paquete lodash.invert y trague

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

3) Probar que 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

Referencias

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

https://lodash.com/

Diferencias entre lodash y subrayado

https://github.com/gulpjs/gulp


¿Por qué está involucrado Gulp aquí? Simplemente ejecute el script ...
Ry-

0

Subrayar js solución

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

Esto me funcionó para obtener la clave / valor del 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 sencillo.

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"

66
No hay garantía de que el orden de los objetos sea el mismo ...
Downgoat

-2

¡Mantenlo simple!

No necesita filtrar el objeto a través de métodos sofisticados o libs, Javascript tiene una función incorporada llamada Object.values .

Ejemplo:

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

Esto devolverá los datos de propiedad del objeto.

Referencias

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.