简体   繁体   English

Javascript - 将值映射到键(反向对象映射)

[英]Javascript - map value to keys (reverse object mapping)

I want to reverse the mapping of an object (which might have duplicate values).我想反转对象的映射(可能有重复的值)。 Example:示例:

const city2country = {
    'Amsterdam': 'Netherlands',
    'Rotterdam': 'Netherlands',
    'Paris': 'France'
};

reverseMapping(city2country) Should output: reverseMapping(city2country)应该输出:

{
    'Netherlands': ['Amsterdam', 'Rotterdam'],
    'France': ['Paris']
}

I've come up with the following, naive solution:我想出了以下幼稚的解决方案:

const reverseMapping = (obj) => {
    const reversed = {};
    Object.keys(obj).forEach((key) => {
        reversed[obj[key]] = reversed[obj[key]] || [];
        reversed[obj[key]].push(key);
    });
    return reversed;
};

But I'm pretty sure there is a neater, shorter way, preferably prototyped so I could simply do:但我很确定有一种更简洁、更短的方法,最好是原型,这样我就可以简单地做:

const country2cities = city2country.reverse();

You could use Object.assign , while respecting the given array of the inserted values.您可以使用Object.assign ,同时尊重给定的插入值数组。

 const city2country = { Amsterdam: 'Netherlands', Rotterdam: 'Netherlands', Paris: 'France' }; const reverseMapping = o => Object.keys(o).reduce((r, k) => Object.assign(r, { [o[k]]: (r[o[k]] || []).concat(k) }), {}) console.log(reverseMapping(city2country));

There is no such built-in function in JavaScript. JavaScript 中没有这样的内置函数。 Your code looks fine, but given that there are so many edge cases here that could wrong, I'd suggesting using invertBy from lodash , which does exactly what you describe.您的代码看起来不错,但考虑到这里有很多可能出错的边缘情况,我建议使用invertBy的 invertBy ,它完全符合您的描述。

Example示例

var object = { 'a': 1, 'b': 2, 'c': 1 }; _.invertBy(object); // => { '1': ['a', 'c'], '2': ['b'] }

You can use something like this to get raid of duplicates first :您可以使用这样的东西来首先获取重复项:

function removeDuplicates(arr, key) {
   if (!(arr instanceof Array) || key && typeof key !== 'string') {
    return false;
   }

  if (key && typeof key === 'string') {
    return arr.filter((obj, index, arr) => {
        return arr.map(mapObj => mapObj[key]).indexOf(obj[key]) === index;
    });

  } else {
    return arr.filter(function(item, index, arr) {
        return arr.indexOf(item) == index;
    });
  }
} 

and then use this to make it reverse :然后使用它使其反转:

function reverseMapping(obj){
  var ret = {};
  for(var key in obj){
  ret[obj[key]] = key;
  }
    return ret;
  }

You could use reduce to save the declaration line reduce .您可以使用 reduce 来保存声明行reduce

Abusing && to check if the map[object[key]] is defined first before using Array.concat .在使用Array.concat之前,滥用&&检查是否首先定义了map[object[key]]

It's shorter, but is it simpler?它更短,但它更简单吗? Probably not, but a bit of fun ;)可能不是,但有点乐趣;)

const reverseMapping = (object) => 
    Object.keys(object).reduce((map, key) => {
        map[object[key]] = map[object[key]] && map[object[key]].concat(key) || [key]
     return map;
    }, {});

You could try getting an array of values and an array of keys from the current object, and setup a new object to hold the result.您可以尝试从当前对象获取一组值和一组键,并设置一个新对象来保存结果。 Then, as you loop through the array of values -然后,当您遍历值数组时 -

  • if the object already has this value as the key, like Netherlands , you create a new array, fetch the already existing value (ex: Rotterdam ), and add this and the new value ( Amsterdam ) to the array, and set up this array as the new value for the Netherlands key.如果对象已经有这个值作为键,比如Netherlands ,你创建一个新数组,获取已经存在的值(例如: Rotterdam ),并将这个值和新值( Amsterdam )添加到数组中,并设置这个数组作为Netherlands键的新值。
  • if the current value doesn't exist in the object, set it up as a new string, ex: France is the key and Paris is the value.如果当前值不存在于对象中,则将其设置为一个新字符串,例如: France是键, Paris是值。

Code -代码 -

 const city2country = { 'Amsterdam': 'Netherlands', 'Rotterdam': 'Netherlands', 'Paris': 'France', }; function reverseMapping(obj) { let values = Object.values(obj); let keys = Object.keys(obj); let result = {} values.forEach((value, index) => { if(!result.hasOwnProperty(value)) { // create new entry result[value] = keys[index]; } else { // duplicate property, create array let temp = []; // get first value temp.push(result[value]); // add second value temp.push(keys[index]); // set value result[value] = temp; } }); console.log(result); return result; } reverseMapping(city2country)

The benefit here is - it adjusts to the structure of your current object - Netherlands being the repeated values, gets an array as it's value in the new object, while France gets a string value Paris as it's property.这里的好处是 - 它会根据您当前对象的结构进行调整 - Netherlands是重复值,在新对象中获得一个数组作为它的值,而France获得一个字符串值Paris作为它的属性。 Of course, it should be very easy to change this.当然,改变这个应该很容易。

Note - Object.values() might not be supported across older browsers.注 - 旧浏览器可能不支持Object.values()

@Nina Scholz answer works well for this exact question. @Nina Scholz 的回答非常适合这个确切的问题。 :thumbsup: :thumbsup:

But if you don't need to keep both values for the Netherlands key ( "Netherlands": ["Amsterdam", "Rotterdam"] ), then this is a little bit shorter and simpler to read:但是,如果您不需要保留荷兰键的两个值"Netherlands": ["Amsterdam", "Rotterdam"] ),那么这会更短更容易阅读:

const city2country = { Amsterdam: 'Netherlands', Rotterdam: 'Netherlands', Paris: 'France' };

console.log(
  Object.entries(city2country).reduce((obj, item) => (obj[item[1]] = item[0]) && obj, {})
);
// outputs `{Netherlands: "Rotterdam", France: "Paris"}`

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM