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.