Swap clé avec la valeur JSON

106

J'ai un objet JSON extrêmement grand structuré comme ceci:

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

J'ai besoin d'une fonction qui peut permuter les valeurs avec des clés dans mon objet et je ne sais pas comment le faire. J'aurais besoin d'une sortie comme celle-ci:

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

Y a-t-il un moyen que je puisse faire cela créerait manuellement un nouvel objet où tout est échangé?
Merci

C1D
la source
1
sont toutes les valeurs des nombres et les nombres se répètent-ils? Si les valeurs se répètent, vous ne pourrez pas les échanger car elles remplaceront les autres, à moins que vous ne changiez leur valeur en une valeur unique. Il pourrait y avoir une meilleure solution quelle est la raison pour laquelle le swap est nécessaire?
Patrick Evans
@PatrickEvans Ce sont tous des chiffres mais ils ne se répètent pas. J'essaye de faire un chiffrement de base.
C1D
2
Il est intéressant de noter qu'une opération "swap" comme celle-ci est problématique pour [au moins] deux raisons: 1) Les valeurs sont converties en chaînes lorsqu'elles deviennent des clés donc ne soyez pas surpris lorsque vous avez des clés "[objet objet]" inattendues. Et 2) les valeurs dupliquées (après conversion en String) sont écrasées. Le n ° 1, au moins, peut être résolu en produisant une carte au lieu d'un objet, ainsi:function swap(obj) {return new Map(Object.entries(x).map([k, v] => [v, k]))}
broofa

Réponses:

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

Exemple ici FIDDLE n'oubliez pas d'allumer votre console pour voir les résultats.


Versions ES6 :

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

Ou en utilisant Array.reduce () et Object.keys ()

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

Ou en utilisant Array.reduce () et Object.entries ()

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

vous pouvez utiliser la fonction lodash _.invert, il peut également utiliser 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'] }
Ohad Sadan
la source
39

En utilisant ES6:

const obj = { a: "aaa", b: "bbb", c: "ccc", d: "ddd" };
Object.assign({}, ...Object.entries(obj).map(([a,b]) => ({ [b]: a })))
grappeq
la source
2
Semble la meilleure solution pour aujourd'hui (2019)! Quelqu'un peut confirmer, n'est-ce pas? Bonne performance? La sémantique est parfaite: nous pouvons voir qu'il s'agit en fait d'une solution simple de "map and swap".
Peter Krauss
1
@ peter-krauss, Vous êtes invités à bricoler avec jsben.ch/gHEtn au cas où j'aurais manqué quelque chose, mais une comparaison informelle entre cette réponse et la réponse de jPO montre que la boucle for de jPO surpasse l'approche de la carte de grappeq de près de 3 contre 1 (au moins sur mon navigateur).
Michael Hays
36

Obtenez les clés de l'objet, puis utilisez la fonction de réduction du tableau pour parcourir chaque clé et définir la valeur comme clé et la clé comme valeur.

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

Patrick Evans
la source
30

Dans ES6 / ES2015, vous pouvez combiner l'utilisation d' Object.keys et réduire avec la nouvelle fonction Object.assign , une fonction de flèche et un nom de propriété calculé pour une solution d'instruction unique assez simple.

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

Si vous transpilez en utilisant l' opérateur de propagation d'objet (étape 3 au moment de l'écriture de ceci), cela simplifiera un peu plus les choses.

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

Enfin, si vous avez Object.entries disponible (étape 4 au moment de la rédaction), vous pouvez nettoyer un peu plus la logique (IMO).

const foo = { a: 1, b: 2, c: 3 };
const bar = Object.entries(foo)
    .reduce((obj, [key, value]) => ({ ...obj, [value]: key }), {});
Joslarson
la source
SyntaxError: /Users/markus/Entwicklung/IT1_Beleg/public/es6/vokabeltrainer.js: jeton inattendu (53:45) 51 | si (btoa) {52 | entrées = Object.entries (entrées)> 53 | .reduce ((obj, [clé, valeur]) => ({... obj, [valeur]: clé}), {}); | ^
Superlokkus
@Superlokkus ma meilleure interprétation de cette sortie d'erreur est que vous ne transpilez pas la syntaxe de propagation d'objets, et à ce jour, je ne connais aucun moteur JavaScript qui la prend en charge de manière native.
joslarson
1
Voir la solution de @ grappeq, semble meilleure (la plus simple!).
Peter Krauss
16

Maintenant que nous avons Object.fromEntries:

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

ou

obj => Object.fromEntries(Object.entries(obj).map(([k, v]) => ([v, k])))
Sc0ttyD
la source
Cela devrait également être une méthode standard de permutation d'objets à partir de la version 12 de Node.js.
Damaged Organic
4

En complément des réponses @joslarson et @jPO:
Sans ES6 nécessaire, vous pouvez utiliser et l' opérateur virgule :Object.keys Array.reduce

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

Certains peuvent trouver cela moche, mais c'est "un peu" plus rapide car le reducene répartit pas toutes les propriétés du objsur chaque boucle.

Vaidd4
la source
Pourtant ... la réponse de jPO surpasse celle-ci de près de 2: 1. jsben.ch/R75aI (je sais que votre commentaire date d'il y a très, très longtemps, mais je commentais la réponse de grappeq et j'ai pensé que j'exécuterais également votre exemple).
Michael Hays
Totalement, une boucle for reste plus rapide que les méthodes forEach, mapou reduce. J'ai fait cette réponse pour avoir une solution one-liner sans avoir besoin d'es6 et être toujours pertinente en termes de rapidité / efficacité.
Vaidd4
Est juin 2019 et ce n'est plus vrai dans le dernier Google Chrome, la différence est maintenant presque inexistante (9:10)
Ivan Castellanos
Cela semble la plus performante des variantes ES6: jsben.ch/HvICq
Brian M. Hunt
4

Essayer

let swap = (o,r={})=> Object.keys(o).map(x=>r[o[x]]=x)&&r;

Kamil Kiełczewski
la source
2

Le plus court que j'ai trouvé avec 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);

Frizzo
la source
1

Utilisation de Ramda :

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

const result = swapKeysWithValues(source);
im.pankratov
la source
1

Je pense qu'il est préférable de faire cette tâche en utilisant un module npm, comme invert-kv.

invert-kv : Inverse la clé / valeur d'un objet. Exemple: {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'}
Huan
la source
1
Pourquoi l'utilisation d'une autre bibliothèque est-elle meilleure qu'une solution en une ligne comme @ Sc0ttyD le suggère, ou même une simple boucle for?
Arel le
1

Avec du pur Ramda dans un style pur et sans point:

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

Ou, avec une version ES6 un peu plus alambiquée, toujours purement fonctionnelle:

const swapKeysAndValues2 = obj => Object
    .entries(obj)
    .reduce((newObj, [key, value]) => ({...newObj, [value]: key}), {})
Pietro Bellone
la source
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);
Anup Agarwal
la source
3
D'où cela objectvient-il?
Maxime Launois
et ce n'est pas ce qui mapest censé faire, vous l'utilisez ici commeforEach
barbsan
Je n'ai jamais utilisé forEach. J'utilise chaque fonction de underscore.js, donc je ne connaissais pas forEach. Merci @barbsan
Anup Agarwal
0

Voici une implémentation fonctionnelle pure du retournement keyset valuesdans ES6:

Manuscrit

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

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

Cela peut rendre votre objet {A : 1, B : 2, C : 3, D : 4},, semblable à un tableau, vous pouvez donc avoir

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"]
Garrett
la source
0

Voici une option qui permutera les clés avec des valeurs mais ne perdra pas les doublons, si votre objet est: {a: 1, b: 2, c: 2}, il renverra toujours un tableau dans la sortie:

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"]}
edi9999
la source