Tukar kunci dengan nilai JSON

106

Saya memiliki objek JSON yang sangat besar yang terstruktur seperti ini:

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

Saya membutuhkan fungsi yang dapat menukar nilai dengan kunci di objek saya dan saya tidak tahu bagaimana melakukannya. Saya membutuhkan keluaran seperti ini:

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

Apakah ada cara saya dapat melakukan ini secara manual membuat objek baru di mana semuanya ditukar?
Terima kasih

C1D
sumber
1
apakah semua nilai adalah angka dan apakah angka tersebut berulang? Jika nilai berulang maka Anda tidak akan dapat menukarnya karena nilai tersebut akan menimpa yang lain, kecuali Anda mengubah nilainya menjadi nilai unik. Mungkin ada solusi yang lebih baik. Apa alasan Anda membutuhkan swap?
Patrick Evans
@PatrickEvans Semuanya angka tetapi tidak berulang. Saya mencoba membuat sandi dasar.
C1D
2
Perlu dicatat bahwa operasi "swap" seperti ini bermasalah karena [setidaknya] dua alasan: 1) Nilai dilemparkan ke String saat menjadi kunci, jadi jangan kaget saat Anda memiliki kunci "[Objek Objek]" yang tidak diharapkan. Dan 2) nilai duplikat (setelah dilemparkan ke String) ditimpa. # 1, setidaknya, dapat diselesaikan dengan menghasilkan Peta, bukan Objek, dengan demikian:function swap(obj) {return new Map(Object.entries(x).map([k, v] => [v, k]))}
broofa

Jawaban:

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

Contoh disini FIDDLE jangan lupa nyalakan console anda untuk melihat hasilnya.


Versi ES6 :

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

Atau menggunakan Array.reduce () & Object.keys ()

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

Atau menggunakan Array.reduce () & Object.entries ()

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

Anda bisa menggunakan fungsi lodash _.invert juga bisa menggunakan 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
sumber
39

Menggunakan ES6:

const obj = { a: "aaa", b: "bbb", c: "ccc", d: "ddd" };
Object.assign({}, ...Object.entries(obj).map(([a,b]) => ({ [b]: a })))
grappeq.dll
sumber
2
Sepertinya solusi yang lebih baik untuk hari ini (2019)! Seseorang bisa memastikan, bukan? Performa bagus? Semantik sempurna: kita dapat melihat bahwa itu benar-benar solusi "peta dan tukar" yang sederhana.
Peter Krauss
1
@ peter-krauss, Anda dipersilakan untuk mengotak-atik jsben.ch/gHEtn jika saya melewatkan sesuatu, tetapi perbandingan biasa antara jawaban ini dan jawaban jPO menunjukkan bahwa loop-for jPO mengungguli pendekatan peta grappeq hampir 3 banding 1 (setidaknya di browser saya ).
Michael Hays
36

Dapatkan kunci objek, lalu gunakan fungsi Reduksi Array untuk melewati setiap kunci dan menetapkan nilai sebagai kunci, dan kunci sebagai nilainya.

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
sumber
30

Di ES6 / ES2015 Anda dapat menggabungkan penggunaan Object.keys dan mengurangi dengan fungsi Object.assign baru , fungsi panah , dan nama properti yang dihitung untuk solusi pernyataan tunggal yang cukup mudah.

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

Jika Anda transpiling menggunakan operator penyebaran objek (tahap 3 saat menulis ini) itu akan menyederhanakan banyak hal.

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

Terakhir, jika Anda memiliki Object.entries yang tersedia (tahap 4 saat penulisan), Anda dapat membersihkan logika lebih banyak sentuhan (IMO).

const foo = { a: 1, b: 2, c: 3 };
const bar = Object.entries(foo)
    .reduce((obj, [key, value]) => ({ ...obj, [value]: key }), {});
joslarson
sumber
SyntaxError: /Users/markus/Entwicklung/IT1_Beleg/public/es6/vokabeltrainer.js: Token tak terduga (53:45) 51 | jika (btoa) {52 | entri = Object.entries (entri)> 53 | .reduce ((obj, [kunci, nilai]) => ({... obj, [nilai]: kunci}), {}); | ^
Superlokkus
@Superlokkus interpretasi terbaik saya dari output kesalahan itu adalah Anda tidak mentranspilasi sintaks penyebaran objek, dan sampai hari ini, saya tidak tahu mesin JavaScript yang mendukungnya secara native.
joslarson
1
Lihat solusi @grappeq, tampaknya lebih baik (paling sederhana!).
Peter Krauss
16

Sekarang kita memiliki Object.fromEntries:

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

atau

obj => Object.fromEntries(Object.entries(obj).map(([k, v]) => ([v, k])))
Sc0ttyD
sumber
Harus menjadi cara standar untuk melakukan pertukaran objek pada Node.js versi 12 juga.
Organik Rusak
4

Sebagai pelengkap dari jawaban @joslarson dan @jPO:
Tanpa perlu ES6, Anda dapat menggunakan dan Operator Koma :Object.keys Array.reduce

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

Beberapa mungkin menganggapnya jelek, tetapi "agak" lebih cepat karena reducetidak menyebarkan semua properti objdi setiap loop.

Vaidd4
sumber
Tetap saja ... jawaban jPO mengungguli yang satu ini dengan hampir 2: 1. jsben.ch/R75aI (Saya tahu komentar Anda berasal dari waktu yang lama, tapi saya mengomentari jawaban grappeq dan berpikir saya akan menjalankan contoh Anda juga).
Michael Hays
Secara total, perulangan for tetap lebih cepat daripada metode forEach, mapatau reduce. Tanggapan ini saya buat agar memiliki solusi satu baris tanpa perlu es6 dan tetap relevan dalam hal kecepatan / efektivitas.
Vaidd4
Apakah Juni 2019 dan itu tidak lagi berlaku di Google Chrome terbaru, perbedaannya sekarang hampir tidak ada (9:10)
Ivan Castellanos
Ini muncul sebagai varian ES6 yang paling berkinerja: jsben.ch/HvICq
Brian M. Hunt
4

Mencoba

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

Kamil Kiełczewski
sumber
2

Yang terpendek yang saya buat dengan menggunakan 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
sumber
1

Menggunakan Ramda :

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

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

Saya percaya lebih baik melakukan tugas ini dengan menggunakan modul npm, seperti invert-kv.

invert-kv : Balikkan kunci / nilai objek. Contoh: {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
sumber
1
Mengapa menggunakan pustaka lain lebih baik daripada solusi satu baris seperti yang disarankan @ Sc0ttyD, atau bahkan for loop sederhana?
Arel
1

Dengan Ramda murni dalam gaya murni dan tanpa poin:

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

Atau, dengan versi ES6 yang sedikit lebih berbelit-belit, masih berfungsi murni:

const swapKeysAndValues2 = obj => Object
    .entries(obj)
    .reduce((newObj, [key, value]) => ({...newObj, [value]: key}), {})
Pietro Bellone
sumber
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
sumber
3
Dari mana objectasalnya
Maxime Launois
dan ini bukan yang mapseharusnya dilakukan, Anda menggunakannya di sini sepertiforEach
barbsan
Saya tidak pernah menggunakan forEach. Saya menggunakan masing-masing fungsi underscore.js jadi tidak tahu tentang forEach. Terima kasih @barbsan
Anup Agarwal
0

Berikut adalah implementasi fungsional murni dari flipping keysdan valuesdi ES6:

TypeScript

  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
sumber
0
function swapKV(obj) {
  const entrySet = Object.entries(obj);
  const reversed = entrySet.map(([k, v])=>[v, k]);
  const result = Object.fromEntries(reversed);
  return result;
}

Ini bisa membuat objek Anda,, {A : 1, B : 2, C : 3, D : 4}seperti array, jadi Anda bisa memilikinya

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
sumber
0

Berikut adalah opsi yang akan menukar kunci dengan nilai tetapi tidak kehilangan duplikat, jika objek Anda adalah: {a: 1, b: 2, c: 2}, itu akan selalu mengembalikan larik di keluaran:

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
sumber