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


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;
  }, {});
}

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'] }

39

Menggunakan ES6:

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

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


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 }), {});

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

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.


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


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


1

Menggunakan Ramda :

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

const result = swapKeysWithValues(source);

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

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}), {})

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


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"]

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"]}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.