Schlüssel mit Wert JSON tauschen


106

Ich habe ein extrem großes JSON-Objekt, das wie folgt aufgebaut ist:

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

Ich brauche eine Funktion, die die Werte mit Schlüsseln in meinem Objekt austauschen kann, und ich weiß nicht, wie es geht. Ich würde eine Ausgabe wie diese benötigen:

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

Gibt es eine Möglichkeit, dies zu tun, indem manuell ein neues Objekt erstellt wird, in dem alles ausgetauscht wird?
Vielen Dank


1
Sind alle Werte Zahlen und wiederholen sich die Zahlen? Wenn sich die Werte wiederholen, können Sie sie nicht austauschen, da sie die anderen überschreiben, es sei denn, Sie ändern ihren Wert in einen eindeutigen Wert. Es könnte eine bessere Lösung geben. Was ist der Grund für die Notwendigkeit des Austauschs?
Patrick Evans

@PatrickEvans Das sind alles Zahlen, aber sie wiederholen sich nicht. Ich versuche, eine grundlegende Chiffre zu erstellen.
C1D

2
Es ist erwähnenswert, dass eine solche "Swap" -Operation aus [mindestens] zwei Gründen problematisch ist: 1) Werte werden in Strings umgewandelt, wenn sie zu Schlüsseln werden. Seien Sie also nicht überrascht, wenn Sie unerwartete "[object Object]" - Schlüssel haben. Und 2) doppelte Werte (nach Umwandlung in String) werden überschrieben. Zumindest # 1 kann gelöst werden, indem eine Karte anstelle eines Objekts erstellt wird, also:function swap(obj) {return new Map(Object.entries(x).map([k, v] => [v, k]))}
broofa

Antworten:


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

Beispiel hier FIDDLE Vergessen Sie nicht, Ihre Konsole einzuschalten , um die Ergebnisse zu sehen.


ES6- Versionen:

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

Oder verwenden Sie Array.reduce () & Object.keys ()

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

Oder verwenden Sie Array.reduce () & Object.entries ()

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

44

Sie können die lodash-Funktion _.invert verwenden. Sie kann auch multivlaue verwenden

 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

Verwenden von ES6:

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

2
Scheint die bessere Lösung für heute (2019) zu sein! Jemand kann es bestätigen, oder? Leistung gut? Semantik ist perfekt: Wir können sehen, dass dies wirklich eine einfache "Map and Swap" -Lösung ist.
Peter Krauss

1
@ peter-krauss, Sie können gerne mit jsben.ch/gHEtn basteln, falls ich etwas verpasst habe, aber ein gelegentlicher Vergleich zwischen dieser Antwort und der Antwort von jPO zeigt, dass die for-Schleife von jPO den Kartenansatz von grappeq um mindestens 3 zu 1 übertrifft in meinem Browser).
Michael Hays

36

Holen Sie sich die Schlüssel des Objekts und verwenden Sie dann die Reduktionsfunktion des Arrays, um jeden Schlüssel durchzugehen und den Wert als Schlüssel und den Schlüssel als Wert festzulegen.

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 können Sie nutzen kombinieren Object.keys und reduzieren mit der neuen Object.assign Funktion, eine Pfeil - Funktion und einem berechneten Eigenschaftsnamen für eine ziemlich einfache einzelne Anweisung Lösung.

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

Wenn Sie mit dem Objektverbreitungsoperator transpilieren (Stufe 3 zum Zeitpunkt des Schreibens), wird dies die Dinge ein wenig weiter vereinfachen.

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

Wenn Sie Object.entries zur Verfügung haben (Stufe 4 zum Zeitpunkt des Schreibens), können Sie die Logik ein wenig mehr bereinigen (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: Unerwartetes Token (53:45) 51 | if (btoa) {52 | Einträge = Object.entries (Einträge)> 53 | .reduce ((obj, [Schlüssel, Wert]) => ({... obj, [Wert]: Schlüssel}), {}); | ^
Superlokkus

@Superlokkus Meine beste Interpretation dieser Fehlerausgabe ist, dass Sie die Objektverbreitungssyntax nicht transpilieren, und bis heute kenne ich keine JavaScript-Engines, die sie nativ unterstützen.
Joslarson

1
Siehe @ grappeqs Lösung, scheint besser (die einfachste!).
Peter Krauss

16

Jetzt, wo wir Object.fromEntries haben:

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

oder

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

Sollte ab Node.js Version 12 auch die Standardmethode für den Objektaustausch sein.
Beschädigte Bio

4

Als Ergänzung zu den Antworten von @joslarson und @jPO:
Ohne ES6 können Sie und den Komma-Operator verwenden :Object.keys Array.reduce

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

Einige mögen es hässlich finden, aber es ist "irgendwie" schneller, da reducees nicht alle Eigenschaften von objauf jeder Schleife verbreitet.


Trotzdem ... jPOs Antwort übertrifft diese um fast 2: 1. jsben.ch/R75aI (Ich weiß, Ihr Kommentar stammt von vor langer, langer Zeit, aber ich habe die Antwort von grappeq kommentiert und dachte, ich würde auch Ihr Beispiel ausführen).
Michael Hays

Völlig, eine for - Schleife bleibt schneller als die forEach, mapoder reduceMethoden. Ich habe diese Antwort gegeben, um eine Einzeiler-Lösung ohne die Notwendigkeit von es6 zu haben und dennoch in Bezug auf Geschwindigkeit / Effektivität relevant zu sein.
Vaidd4

Ist Juni 2019 und das ist in Google Chrome nicht mehr der Fall, ist der Unterschied jetzt fast nicht mehr vorhanden (9:10)
Ivan Castellanos

Dies scheint die leistungsstärkste der ES6-Varianten zu sein: jsben.ch/HvICq
Brian M. Hunt


2

Die kürzeste, die ich mir mit ES6 ausgedacht habe.

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

Verwenden von Ramda :

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

const result = swapKeysWithValues(source);

1

Ich glaube, es ist besser, diese Aufgabe mit einem npm-Modul zu erledigen, wie z invert-kv.

invert-kv : Invertiert den Schlüssel / Wert eines Objekts. Beispiel: {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
Warum ist die Verwendung einer weiteren Bibliothek besser als eine einzeilige Lösung wie von @ Sc0ttyD vorgeschlagen oder sogar eine einfache for-Schleife?
Arel

1

Mit reinem Ramda in einem reinen und punktfreien Stil:

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

Oder mit einer etwas komplizierteren ES6-Version immer noch rein funktional:

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
Woher kommt das object?
Maxime Launois

und das ist nicht was mapsoll tun, du benutzt es hier wieforEach
barbsan

Ich habe nie für jeden verwendet. Ich benutze jede Funktion von underscore.js, wusste also nichts über forEach. Vielen Dank, dass Sie @barbsan
Anup Agarwal

0

Hier ist eine rein funktionale Implementierung von Flipping keysund valuesin ES6:

Typoskript

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

Dies kann Ihr Objekt {A : 1, B : 2, C : 3, D : 4}Array-artig machen, so dass Sie haben können

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

Hier ist eine Option, die Schlüssel mit Werten austauscht, aber keine Duplikate verliert. Wenn Ihr Objekt: {a: 1, b: 2, c: 2} lautet, gibt es immer ein Array in der Ausgabe zurück:

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"]}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.