Trao đổi khóa với giá trị JSON


106

Tôi có một đối tượng JSON cực kỳ lớn được cấu trúc như thế này:

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

Tôi cần một hàm có thể hoán đổi các giá trị bằng các khóa trong đối tượng của mình và tôi không biết cách thực hiện. Tôi sẽ cần một đầu ra như thế này:

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

Có cách nào tôi có thể làm điều này để tạo một đối tượng mới theo cách thủ công nơi mọi thứ được hoán đổi không?
Cảm ơn


1
có phải tất cả các giá trị là số và các số có lặp lại không? Nếu các giá trị lặp lại thì bạn sẽ không thể hoán đổi chúng vì chúng sẽ ghi đè lên các giá trị khác, trừ khi bạn thay đổi giá trị của chúng thành một giá trị duy nhất nào đó. Có thể có một giải pháp tốt hơn lý do cần hoán đổi là gì?
Patrick Evans

@PatrickEvans Tất cả đều là số nhưng chúng không lặp lại. Tôi đang cố tạo mật mã cơ bản.
C1D

2
Cần lưu ý rằng thao tác "hoán đổi" như thế này có vấn đề vì [ít nhất] hai lý do: 1) Các giá trị được truyền đến Chuỗi khi chúng trở thành khóa, vì vậy đừng ngạc nhiên khi bạn có khóa "[đối tượng Đối tượng]" không mong muốn. Và 2) các giá trị trùng lặp (sau khi truyền sang Chuỗi) bị ghi đè. # 1, ít nhất, có thể được giải quyết bằng cách tạo ra một bản đồ thay vì một đối tượng, thusly:function swap(obj) {return new Map(Object.entries(x).map([k, v] => [v, k]))}
broofa

Câu trả lời:


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

Ví dụ ở đây FIDDLE đừng quên bật bảng điều khiển của bạn để xem kết quả.


Các phiên bản ES6 :

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

Hoặc sử dụng Array.reduce () & Object.keys ()

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

Hoặc sử dụng Array.reduce () & Object.entries ()

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

44

bạn có thể sử dụng hàm lodash _. invert nó cũng có thể sử dụng 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

Sử dụng ES6:

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

2
Có vẻ như giải pháp tốt hơn cho ngày hôm nay (2019)! Ai đó có thể xác nhận, phải không? Hiệu suất tốt? Ngữ nghĩa là hoàn hảo: chúng ta có thể thấy đó thực sự là một giải pháp "bản đồ và hoán đổi" đơn giản.
Peter Krauss

1
@ peter-krauss, Bạn có thể tự mày mò với jsben.ch/gHEtn trong trường hợp tôi bỏ lỡ điều gì đó, nhưng so sánh thông thường giữa câu trả lời này và câu trả lời của jPO cho thấy rằng vòng lặp của jPO tốt hơn cách tiếp cận bản đồ của grappeq gần 3 đến 1 (ít nhất trên trình duyệt của tôi ).
Michael Hays

36

Lấy các khóa của đối tượng, sau đó sử dụng chức năng giảm của Mảng để đi qua từng khóa và đặt giá trị làm khóa và khóa làm giá trị.

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

Trong ES6 / ES2015 bạn có thể kết hợp sử dụng các Object.keysgiảm với mới Object.assign chức năng, một chức năng mũi tên , và một tên thuộc tính cho một giải pháp câu lệnh khá đơn giản.

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

Nếu bạn đang chuyển đổi bằng cách sử dụng toán tử lây lan đối tượng (giai đoạn 3 kể từ khi viết bài này) sẽ đơn giản hóa mọi thứ hơn một chút.

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

Cuối cùng, nếu bạn có sẵn Object.entries (giai đoạn 4 khi viết bài), bạn có thể làm sạch logic hơn (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: Mã thông báo không mong đợi (53:45) 51 | nếu (btoa) {52 | entry = Object.entries (entry)> 53 | .reduce ((obj, [key, value]) => ({... obj, [value]: key}), {}); | ^
Superlokkus

@Superlokkus cách giải thích tốt nhất của tôi về đầu ra lỗi đó là bạn không chuyển đổi cú pháp lây lan đối tượng và cho đến hôm nay, tôi không biết bất kỳ công cụ JavaScript nào hỗ trợ nó nguyên bản.
joslarson,

1
Xem giải pháp của @ grappeq, có vẻ tốt hơn (đơn giản nhất!).
Peter Krauss

16

Bây giờ chúng ta có Object.fromEntries:

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

hoặc là

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

Cũng nên là cách tiêu chuẩn để thực hiện hoán đổi đối tượng kể từ phiên bản Node.js 12.
Hư hỏng hữu cơ

4

Là phần bổ sung của câu trả lời @joslarson và @jPO:
Không cần ES6, bạn có thể sử dụng và Toán tử dấu phẩy :Object.keys Array.reduce

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

Một số người có thể thấy nó xấu xí, nhưng nó "hơi" nhanh hơn vì reducekhông lan truyền tất cả các thuộc tính của objmỗi vòng lặp.


Tuy nhiên ... câu trả lời của jPO vượt trội hơn câu trả lời này gần 2: 1. jsben.ch/R75aI (Tôi biết bình luận của bạn đã có từ lâu, rất lâu trước đây, nhưng tôi đã bình luận về câu trả lời của grappeq và tôi nghĩ rằng tôi cũng sẽ chạy ví dụ của bạn).
Michael Hays

Về tổng thể, vòng lặp for vẫn nhanh hơn so với các phương thức forEach, maphoặc reduce. Tôi thực hiện phản hồi này để có giải pháp một lớp mà không cần đến es6 và vẫn phù hợp về tốc độ / hiệu quả.
Vaidd4

Là tháng 6 năm 2019 và đó là không còn đúng trong mới nhất của Google Chrome, sự khác biệt tại là gần không tồn tại (9:10)
Ivan Castellanos

Điều này dường như performant hầu hết các ES6 biến thể: jsben.ch/HvICq
Brian M. Hunt


2

Điều ngắn nhất mà tôi nghĩ ra bằng cách sử dụng 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

Sử dụng Ramda :

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

const result = swapKeysWithValues(source);

1

Tôi tin rằng tốt hơn nên thực hiện tác vụ này bằng cách sử dụng mô-đun npm, chẳng hạn như invert-kv.

invert-kv : Đảo khóa / giá trị của một đối tượng. Ví dụ: {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
Tại sao lại sử dụng một thư viện khác tốt hơn giải pháp một dòng như @ Sc0ttyD đề xuất, hoặc thậm chí là một vòng lặp for đơn giản?
Arel

1

Với Ramda thuần túy theo phong cách thuần túy và không có điểm nhấn:

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

Hoặc, với phiên bản ES6 phức tạp hơn một chút, vẫn hoạt động thuần túy:

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
Điều này objectđến từ đâu?
Maxime Launois

và đây không phải là những gì mapcó nghĩa vụ phải làm, bạn đang sử dụng nó ở đây như thếforEach
barbsan

Tôi chưa bao giờ sử dụng forEach. Tôi sử dụng từng hàm của underscore.js nên không biết về forEach. Cảm ơn bạn @barbsan
Anup Agarwal

0

Đây là một triển khai chức năng thuần túy của phép lật keysvaluestrong 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;
}

Điều này có thể làm cho đối tượng của bạn, {A : 1, B : 2, C : 3, D : 4}giống như mảng, vì vậy bạn có thể có

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

Đây là một tùy chọn sẽ hoán đổi các khóa với các giá trị nhưng không làm mất các bản sao, nếu đối tượng của bạn là: {a: 1, b: 2, c: 2}, nó sẽ luôn trả về một mảng trong đầu ra:

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"]}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.