交换值为JSON的键


106

我有一个结构非常大的JSON对象,如下所示:

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

我需要一个可以与对象中的键交换值的函数,但我不知道该怎么做。我需要这样的输出:

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

有什么办法可以手动创建一个交换所有内容的新对象?
谢谢


1
值都是数字,数字重复吗?如果重复这些值,则您将无法交换它们,因为它们会覆盖其他值,除非您将其值更改为某个唯一值。可能有更好的解决方案,需要进行交换的原因是什么?
Patrick Evans 2014年

@PatrickEvans它们都是数字,但不再重复。我正在尝试建立基本密码。
C1D 2014年

2
值得注意的是,这样的“交换”操作至少有两个原因是有问题的:1)当值成为键时,值会强制转换为字符串,因此当您有意外的“ [object Object]”键时不要感到惊讶。2)重复值(强制转换为String之后)将被覆盖。#1至少可以通过生成Map而不是Object来解决,因此:function swap(obj) {return new Map(Object.entries(x).map([k, v] => [v, k]))}
broofa

Answers:


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

这里的示例FIDDLE不要忘记打开控制台以查看结果。


ES6版本:

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

或使用Array.reduce()Object.keys()

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

或使用Array.reduce()Object.entries()

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


39

使用ES6:

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

2
似乎是当今(2019年)更好的解决方案!有人可以确认吗?性能好吗?语义是完美的:我们可以看到这确实是一个简单的“映射和交换”解决方案。
彼得·克劳斯

1
@ peter- krauss,如果您错过了某些内容,欢迎您使用jsben.ch/gHEtn进行修改,但是此答案与jPO的答案之间的随意比较显示,jPO的for循环性能比grappeq的map方法高出近3比1(至少在我的浏览器上)。
Michael Hays

36

获取对象的键,然后使用数组的reduce函数遍历每个键,并将值设置为键,并将键设置为值。

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

在ES6 / ES2015中,您可以结合使用Object.keys并通过新的Object.assign函数,arrow函数简化的单语句解决方案的计算属性名称简化操作

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

如果使用对象散布运算符(在撰写本文时为第3阶段)进行转译,则会进一步简化操作。

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

最后,如果有Object.entries可用(撰写本文时为第4阶段),则可以多做一些清理(IMO)的逻辑。

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

语法错误:/Users/markus/Entwicklung/IT1_Beleg/public/es6/vokabeltrainer.js:意外令牌(53:45)51 | 如果(btoa){52 | 条目= Object.entries(条目)> 53 | .reduce((obj,[key,value])=>({... obj,[value]:key}),{}); | ^
Superlokkus

@Superlokkus我对该错误输出的最佳解释是您没有在转译对象传播语法,并且到目前为止,我还不知道有任何原生支持它的JavaScript引擎。
joslarson

1
参见@grappeq的解决方案,似乎更好(最简单!)。
彼得·克劳斯

16

现在我们有了Object.fromEntries:

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

要么

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

从Node.js版本12开始,应该也是执行对象交换的标准方法。
损坏的有机

4

作为@joslarson和@jPO答案的补充:
无需ES6,您可以使用和逗号运算符Object.keys Array.reduce

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

某些人可能会发现它很丑陋,但是它的“种类”更快,因为reduce它不会obj在每个循环中传播的所有属性。


仍然... jPO的答案几乎比这个答案高2:1。jsben.ch/R75aI (我很早以前就知道您的评论,但是我正在评论grappeq的答案,并认为我也将运行您的示例)。
Michael Hays

完全,一个for循环保持较快那么forEachmapreduce方法。我做出此响应是为了获得无需es6的单线解决方案,并且在速度/效果方面仍然很重要。
Vaidd4

是2019年6月,而在最新的Google Chrome浏览器中已不再是这样,两者之间的差异现在几乎不存在(9:10)
Ivan Castellanos

这似乎是ES6变体中性能最高的:jsben.ch/HvICq
Brian M. Hunt


2

最短的一个是我想到使用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

使用Ramda

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

const result = swapKeysWithValues(source);

1

我认为最好通过使用npm模块来完成此任务invert-kv

invert-kv:反转对象的键/值。示例:{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
为什么使用另一个库比@ Sc0ttyD建议的单行解决方案甚至是简单的for循环更好?
Arel

1

采用纯Ramda的纯净无点样式:

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

或者,使用复杂得多的ES6版本,仍可以使用纯功能:

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
object是哪里来的?
Maxime Launois

这不是map应该做的,您正在这里使用它,例如forEach
barbsan

我从来没有用过。我使用underscore.js的每个函数,所以不了解forEach。谢谢@barbsan
Anup Agarwal,

0

这里是翻转的纯功能的实现keys,并values在ES6:

打字稿

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

这可以使您的对象{A : 1, B : 2, C : 3, D : 4}类似于数组,因此您可以

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

这是一个将键与值交换但不会丢失重复项的选项,如果您的对象是:{a:1,b:2,c:2},它将始终在输出中返回一个数组:

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"]}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.