Intercambiar clave con valor JSON


106

Tengo un objeto JSON extremadamente grande estructurado así:

{A : 1, B : 2, C : 3, D : 4}

Necesito una función que pueda intercambiar los valores con claves en mi objeto y no sé cómo hacerlo. Necesitaría una salida como esta:

{1 : A, 2 : B, 3 : C, 4 : D}

¿Hay alguna forma de que pueda hacer esto? ¿Crearía manualmente un nuevo objeto donde todo se intercambia?
Gracias


1
¿Son todos los valores números y se repiten los números? Si los valores se repiten, no podrá intercambiarlos, ya que sobrescribirán a los demás, a menos que cambie su valor a un valor único. Podría haber una solución mejor, ¿cuál es la razón por la que se necesita el intercambio?
Patrick Evans

@PatrickEvans Son todos números pero no se repiten. Estoy intentando hacer un cifrado básico.
C1D

2
Vale la pena señalar que una operación de "intercambio" como esta es problemática por [al menos] dos razones: 1) Los valores se envían a cadenas cuando se convierten en claves, así que no se sorprenda cuando tenga claves inesperadas "[objeto Objeto]". Y 2) los valores duplicados (después de convertirlos en String) se sobrescriben. # 1, al menos, puede ser resuelto mediante la producción de un mapa en lugar de un objeto, de esta manera:function swap(obj) {return new Map(Object.entries(x).map([k, v] => [v, k]))}
broofa

Respuestas:


118
function swap(json){
  var ret = {};
  for(var key in json){
    ret[json[key]] = key;
  }
  return ret;
}

Ejemplo aquí FIDDLE no olvide encender su consola para ver los resultados.


Versiones ES6 :

static objectFlip(obj) {
  const ret = {};
  Object.keys(obj).forEach(key => {
    ret[obj[key]] = key;
  });
  return ret;
}

O usando Array.reduce () y Object.keys ()

static objectFlip(obj) {
  return Object.keys(obj).reduce((ret, key) => {
    ret[obj[key]] = key;
    return ret;
  }, {});
}

O usando Array.reduce () y Object.entries ()

static objectFlip(obj) {
  return Object.entries(obj).reduce((ret, entry) => {
    const [ key, value ] = entry;
    ret[ value ] = key;
    return ret;
  }, {});
}

44

puede usar la función lodash _.invertir también puede usar multivlaue

 var object = { 'a': 1, 'b': 2, 'c': 1 };

  _.invert(object);
  // => { '1': 'c', '2': 'b' }

  // with `multiValue`
  _.invert(object, true);
  // => { '1': ['a', 'c'], '2': ['b'] }

39

Usando ES6:

const obj = { a: "aaa", b: "bbb", c: "ccc", d: "ddd" };
Object.assign({}, ...Object.entries(obj).map(([a,b]) => ({ [b]: a })))

2
¡Parece la mejor solución para hoy (2019)! Alguien puede confirmarlo, ¿verdad? Buen rendimiento? La semántica es perfecta: podemos ver que es realmente una solución simple de "mapa e intercambio".
Peter Krauss

1
@ peter-krauss, puede jugar con jsben.ch/gHEtn en caso de que me haya perdido algo, pero una comparación casual entre esta respuesta y la respuesta de jPO muestra que el bucle for de jPO supera al enfoque de mapa de grappeq en casi 3 a 1 (al menos en mi navegador).
Michael Hays

36

Obtenga las claves del objeto y luego use la función de reducción de Array para revisar cada clave y establecer el valor como clave y la clave como valor.

const data = {
  A: 1,
  B: 2,
  C: 3,
  D: 4
}
const newData = Object.keys(data).reduce(function(obj, key) {
  obj[data[key]] = key;
  return obj;
}, {});
console.log(newData);


30

En ES6 / ES2015 puede combinar el uso de Object.keys y reducir con la nueva función Object.assign , una función de flecha y un nombre de propiedad calculado para una solución de declaración única bastante sencilla.

const foo = { a: 1, b: 2, c: 3 };
const bar = Object.keys(foo)
    .reduce((obj, key) => Object.assign({}, obj, { [foo[key]]: key }), {});

Si está transpilando usando el operador de extensión de objetos (etapa 3 al momento de escribir esto), eso simplificará las cosas un poco más.

const foo = { a: 1, b: 2, c: 3 };
const bar = Object.keys(foo)
    .reduce((obj, key) => ({ ...obj, [foo[key]]: key }), {});

Finalmente, si tiene Object.entries disponibles (etapa 4 a partir de la escritura), puede limpiar la lógica un poco más (IMO).

const foo = { a: 1, b: 2, c: 3 };
const bar = Object.entries(foo)
    .reduce((obj, [key, value]) => ({ ...obj, [value]: key }), {});

SyntaxError: /Users/markus/Entwicklung/IT1_Beleg/public/es6/vokabeltrainer.js: Token inesperado (53:45) 51 | si (btoa) {52 | entradas = Objeto.entries (entradas)> 53 | .reduce ((obj, [clave, valor]) => ({... obj, [valor]: clave}), {}); | ^
Superlokkus

@Superlokkus, mi mejor interpretación de ese resultado de error es que no está transpilando la sintaxis de propagación del objeto y, a día de hoy, no conozco ningún motor de JavaScript que lo admita de forma nativa.
Joslarson

1
Vea la solución de @grappeq, parece mejor (¡la más simple!).
Peter Krauss

16

Ahora que tenemos Object.fromEntries:

obj => Object.fromEntries(Object.entries(obj).map(a => a.reverse()))

o

obj => Object.fromEntries(Object.entries(obj).map(([k, v]) => ([v, k])))

También debería ser una forma estándar de hacer intercambio de objetos a partir de la versión 12 de Node.js.
Orgánico dañado

4

Como complemento de las respuestas de @joslarson y @jPO:
Sin necesidad de ES6, puede usar y el operador de coma :Object.keys Array.reduce

Object.keys(foo).reduce((obj, key) => (obj[foo[key]] = key, obj), {});

Algunos pueden encontrarlo feo, pero es "un poco" más rápido ya reduceque no distribuye todas las propiedades de objen cada bucle.


Aún así ... la respuesta de jPO supera a esta en casi 2: 1. jsben.ch/R75aI (sé que su comentario fue de hace mucho, mucho tiempo, pero estaba comentando la respuesta de grappeq y pensé que también ejecutaría su ejemplo).
Michael Hays

Totalmente, un bucle for sigue siendo más rápido que los métodos forEach, mapo reduce. Hice esta respuesta para tener una solución de una sola línea sin la necesidad de es6 y seguir siendo relevante en términos de velocidad / efectividad.
Vaidd4

Es junio de 2019 y eso ya no es cierto en la última versión de Google Chrome, la diferencia ahora es casi inexistente (9:10)
Ivan Castellanos

Esta parece la más eficaz
Brian M. Hunt


2

El más corto que se me ocurrió usando ES6 ..

const original = {
 first: 1,
 second: 2,
 third: 3,
 fourth: 4,
};


const modified = Object
  .entries(original)
  .reduce((all, [key, value]) => ({ ...all, [value]: key }), {});

console.log('modified result:', modified);


1

Usando Ramda :

const swapKeysWithValues = 
  R.pipe(
    R.keys,
    R.reduce((obj, k) => R.assoc(source[k], k, obj), {})
  );

const result = swapKeysWithValues(source);

1

Creo que es mejor hacer esta tarea usando un módulo npm, como invert-kv.

invert-kv : invierte la clave / valor de un objeto. Ejemplo: {foo: 'bar'} → {bar: 'foo'}

https://www.npmjs.com/package/invert-kv

const invertKv = require('invert-kv');

invertKv({foo: 'bar', unicorn: 'rainbow'});
//=> {bar: 'foo', rainbow: 'unicorn'}

1
¿Por qué usar otra biblioteca es mejor que una solución de una línea como sugiere @ Sc0ttyD, o incluso un bucle for simple?
Arel

1

Con Ramda puro en un estilo puro y sin puntos:

const swapKeysAndValues = R.pipe(
   R.toPairs,
   R.map(R.reverse),
   R.fromPairs,
);

O, con una versión ES6 un poco más complicada, todavía puramente funcional:

const swapKeysAndValues2 = obj => Object
    .entries(obj)
    .reduce((newObj, [key, value]) => ({...newObj, [value]: key}), {})

0
    var data = {A : 1, B : 2, C : 3, D : 4}
    var newData = {};
    Object.keys(data).forEach(function(key){newData[data[key]]=key});
    console.log(newData);

3
De donde objectviene esto
Maxime Launois

y esto no es lo que mapse supone que debe hacer, lo estás usando aquí comoforEach
barbsan

Nunca usé forEach. Utilizo las funciones de underscore.js, por lo que no sabía nada sobre forEach. Gracias @barbsan
Anup Agarwal

0

Aquí hay una implementación funcional pura de voltear keysy valuesen ES6:

Mecanografiado

  const flipKeyValues = (originalObj: {[key: string]: string}): {[key: string]: string} => {
    if(typeof originalObj === "object" && originalObj !== null ) {
      return Object
      .entries(originalObj)
      .reduce((
        acc: {[key: string]: string}, 
        [key, value]: [string, string],
      ) => {
        acc[value] = key
        return acc;
      }, {})
    } else {
      return {};
    }
  }

JavaScript

const flipKeyValues = (originalObj) => {
    if(typeof originalObj === "object" && originalObj !== null ) {
        return Object
        .entries(originalObj)
        .reduce((acc, [key, value]) => {
          acc[value] = key
          return acc;
        }, {})
    } else {
        return {};
    }
}

const obj = {foo: 'bar'}
console.log("ORIGINAL: ", obj)
console.log("FLIPPED: ", flipKeyValues(obj))


0
function swapKV(obj) {
  const entrySet = Object.entries(obj);
  const reversed = entrySet.map(([k, v])=>[v, k]);
  const result = Object.fromEntries(reversed);
  return result;
}

Esto puede hacer que su objeto, {A : 1, B : 2, C : 3, D : 4}parezca una matriz, por lo que puede tener

const o = {A : 1, B : 2, C : 3, D : 4}
const arrayLike = swapKV(o);
arrayLike.length = 5;
const array = Array.from(arrayLike);
array.shift(); // undefined
array; // ["A", "B", "C", "D"]

0

Aquí hay una opción que intercambiará claves con valores pero no perderá duplicados, si su objeto es: {a: 1, b: 2, c: 2}, siempre devolverá una matriz en la salida:

function swapMap(map) {
    const invertedMap = {};
    for (const key in map) {
        const value = map[key];
        invertedMap[value] = invertedMap[value] || [];
        invertedMap[value].push(key);
    }
    return invertedMap;
}
swapMap({a: "1", b: "2", c: "2"})
// Returns => {"1": ["a"], "2":["b", "c"]}
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.