Scambia la chiave con il valore JSON


106

Ho un oggetto JSON estremamente grande strutturato in questo modo:

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

Ho bisogno di una funzione che possa scambiare i valori con le chiavi nel mio oggetto e non so come farlo. Avrei bisogno di un output come questo:

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

C'è un modo in cui posso farlo se crei manualmente un nuovo oggetto in cui tutto viene scambiato?
Grazie


1
sono tutti valori numeri e i numeri si ripetono? Se i valori si ripetono, non sarai in grado di scambiarli poiché sovrascriveranno gli altri, a meno che non modifichi il loro valore con un valore univoco. Potrebbe esserci una soluzione migliore qual è il motivo per cui è necessario lo scambio?
Patrick Evans

@PatrickEvans Sono tutti numeri ma non si ripetono. Sto cercando di creare un codice di base.
C1D

2
Vale la pena notare che un'operazione di "scambio" come questa è problematica per [almeno] due ragioni: 1) I valori vengono lanciati alle stringhe quando diventano chiavi, quindi non sorprenderti se hai chiavi "[Object Object]" inaspettate. E 2) i valori duplicati (dopo il cast su String) vengono sovrascritti. # 1, almeno, può essere risolto producendo una mappa invece di un oggetto, quindi:function swap(obj) {return new Map(Object.entries(x).map([k, v] => [v, k]))}
broofa

Risposte:


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

Esempio qui FIDDLE non dimenticare di accendere la tua console per vedere i risultati.


Versioni ES6 :

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

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

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

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

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

44

puoi usare la funzione lodash _.invert può anche usare 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

Utilizzando ES6:

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

2
Sembra la soluzione migliore per i giorni nostri (2019)! Qualcuno può confermare, vero? Buone prestazioni? La semantica è perfetta: possiamo vedere che è davvero una semplice soluzione di "mappa e scambio".
Peter Krauss

1
@ peter-krauss, sei il benvenuto ad armeggiare con jsben.ch/gHEtn nel caso mi sia perso qualcosa, ma un confronto casuale tra questa risposta e la risposta di jPO mostra che il ciclo for di jPO supera l'approccio della mappa di grappeq di quasi 3 a 1 (almeno sul mio browser).
Michael Hays,

36

Ottieni le chiavi dell'oggetto, quindi usa la funzione di riduzione di Array per passare attraverso ogni chiave e impostare il valore come chiave e la chiave come valore.

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

In ES6 / ES2015 è possibile combinare l'uso di Object.keys e reduce con la nuova funzione Object.assign , una funzione freccia e un nome di proprietà calcolato per una soluzione a istruzione singola piuttosto semplice.

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

Se stai traspilando usando l' operatore di diffusione degli oggetti (fase 3 al momento della stesura di questo), semplificherai ulteriormente le cose.

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

Infine, se hai Object.entries disponibili (fase 4 al momento della scrittura), puoi ripulire la logica un tocco in più (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 imprevisto (53:45) 51 | se (btoa) {52 | voci = voci.oggetto (voci)> 53 | .reduce ((obj, [key, value]) => ({... obj, [value]: key}), {}); | ^
Superlokkus

@Superlokkus, la mia migliore interpretazione dell'output di errore è che non stai traspilando la sintassi di diffusione degli oggetti e, ad oggi, non conosco alcun motore JavaScript che la supporti in modo nativo.
joslarson

1
Vedi la soluzione di @ grappeq, sembra migliore (la più semplice!).
Peter Krauss

16

Ora che abbiamo Object.fromEntries:

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

o

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

Dovrebbe essere un modo standard per eseguire lo scambio di oggetti anche dalla versione 12 di Node.js.
Organico danneggiato

4

Come complemento delle risposte @joslarson e @jPO:
senza bisogno di ES6, puoi usare e l' operatore virgola :Object.keys Array.reduce

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

Alcuni potrebbero trovarlo brutto, ma è "un po '" più veloce in quanto reducenon diffonde tutte le proprietà di objsu ogni ciclo.


Tuttavia ... la risposta di jPO supera questa di quasi 2: 1. jsben.ch/R75aI (So ​​che il tuo commento risale a molto, molto tempo fa, ma stavo commentando la risposta di grappeq e ho pensato di eseguire anche il tuo esempio).
Michael Hays

In totale, un ciclo for rimane più veloce dei metodi forEach, mapo reduce. Ho fatto questa risposta per avere una soluzione one-liner senza la necessità di es6 ed essere comunque rilevante in termini di velocità / efficacia.
Vaidd4

È giugno 2019 e questo non è più vero nell'ultimo Google Chrome, la differenza è ormai quasi inesistente (9:10)
Ivan Castellanos

Questa sembra la più performante delle varianti ES6: jsben.ch/HvICq
Brian M. Hunt


2

Quello più breve che ho trovato 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

Utilizzando Ramda :

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

const result = swapKeysWithValues(source);

1

Credo che sia meglio eseguire questa operazione utilizzando un modulo npm, come invert-kv.

invert-kv : inverte la chiave / valore di un oggetto. Esempio: {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
Perché usare ancora un'altra libreria è meglio di una soluzione su una riga come suggerisce @ Sc0ttyD, o anche un semplice ciclo for?
Arel

1

Con Ramda puro in uno stile puro e senza punti:

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

Oppure, con una versione ES6 un po 'più contorta, pur sempre funzionale:

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
Da dove viene questo object?
Maxime Launois

e questo non è quello che mapdovrebbe fare, lo stai usando qui comeforEach
barbsan il

Non ho mai usato forEach. Uso ogni funzione di underscore.js, quindi non sapevo di forEach. Grazie @barbsan
Anup Agarwal,

0

Ecco una pura implementazione funzionale del flipping keyse valuesin ES6:

Dattiloscritto

  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;
}

Questo può rendere il tuo oggetto, {A : 1, B : 2, C : 3, D : 4}simile a un array, quindi puoi avere

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

Ecco un'opzione che scambierà le chiavi con i valori ma non perderà i duplicati, se il tuo oggetto è: {a: 1, b: 2, c: 2}, restituirà sempre un array nell'output:

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"]}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.