如何在JavaScript中生成反转对象的键值?

时间:2015-07-23 14:20:51

标签: javascript key inverted-index

更新

我已调整/更正了示例对象,因为它们之前包含错误。

我有一个如下所示的映射对象:

var AtoB = {
  "amore"   : "love",
  "alimenti": "food",
  "Bier"    : "beer"
};

允许映射一种方式,即AtoB["love"]产生"amore"。我可以手工添加一个反面,即。

var BtoA = {
  "love": "amore",
  "food": "alimenti",
  "beer": "Bier"
};

无论如何,两个对象同步会很麻烦,我想在Javascript中以编程方式创建BtoA。是否有某种function xyz()产生var BtoA = xyz(AtoB);

上面的示例可以扩展为包含问题(例如,如果我有太多"beer"

var AtoB = {
  "amore"   : "love",
  "alimenti": "food",
  "Bier"    : "beer"
  "cerveza" : "beer",
  "pivo"    : "beer",
  "birra"   : "beer",
  "cerveja" : "beer"
};

因为这不是一对一的映射。在amateuer数学术语中它不是一个不可逆的函数?

为了让事情变得更复杂,我有一个灾难的秘诀。

var makeStuff = {
  "agriculture": "food",
  "hops" : {
    "water": {
      "malt": "beer"},
    "malt": {
      "water": "beer"}},
  "water" : {
    "hops": {
      "malt": "beer"},
    "malt": {
      "hops": "beer"}},
  "malt" : {
    "water": {
      "hops": "beer"},
    "hops": {
      "water": "beer"}}
  };

反转这个嵌套的 javascript对象,似乎对这样的xyz()函数更加挑剔。无论如何也许有这样一个xyz()函数,那么我很乐意接受这个作为这个问题的答案

2 个答案:

答案 0 :(得分:1)

很简单。以下是反向键值的代码。

var inverse= (function inv(param){

for(var attr in param) {
    if(param.hasOwnProperty(attr)) {
        if(typeof param[attr]==="string") {
            param[param[attr]] = attr;
            delete param[attr];                
        } else if (Object.prototype.toString.call(param[attr]) === "[object Object]") {
            param[attr] = inv(param[attr]);
        }
    }
}
return param;
});

要将结果输入其他对象,请将其初始化为空并分配。像

var BtoA = {};
BtoA = inverse(AtoB);

而且,JSON:

var AtoB = {
  "love": "amore",
  "food": "alimenti",
  "beer": "Bier",
  "beer": "cerveza",
  "beer": "pivo",
  "beer": "birra",
  "beer": "cerveja",
};

只有三个属性,因为JSON是字典数据结构:新密钥将替换旧密钥。所以上面的JSON实际上就像:

{love: "amore", food: "alimenti", beer: "cerveja"}

因此,反转上面给出的JSON(AtoB)将导致只有三个属性的反转,最终结果将是:

{amore: "love", alimenti: "food", cerveja: "beer"}

答案 1 :(得分:0)

如果目的/目标是简单的反转(即没有嵌套的对象结构;没有多个值),则answer from Muhammad imran有效。

显然,这是最好的结果,如果没有创建进一步的技巧,则涵盖对象中的key->值关系是这样的事实:

  • 唯一
  • 值可以 muliple

观察上面的啤酒示例,在倒置中信息丢失有些令人难以置信。因此,这个答案应该补充和丰富,并提供一种可以存储信息的方式。实现它的方法是在生成的反转对象中使用Javascript Arrays,以允许存储潜在的ambigious新值。例如。

var BeerAtoB = {
  "amore"   : "love",
  "alimenti": "food",
  "Bier"    : "beer",
  "cerveza" : "beer",
  "pivo"    : "beer",
  "birra"   : "beer",
  "cerveja" : "beer"
};

允许翻译(de,es,pl / cz,it,pt)"啤酒"英语最好的存储 这个信息在倒置中也是

var BeerBtoA = {
  "love" : "amore",
  "food" : "alimenti",
  "beer" : [ "Bier" ,
              "cerveza", 
              "pivo",
              "birra",
              "cerveja"
           ]
};

一个版本,其中较少的信息丢失和原始价值的多重性"啤酒"联合,倒置的关键"啤酒"现在

为了实现这一点,我做了一个增强的反转功能

function invertObject(obj) 
{
    var invertedObject = {};
    // make a stack and prime it with the obj
    var stack = [];
    stack.push({"way":[],"obj":obj});

    // while stuff on the stack
    while (stack.length) 
    {
        var way= stack[0].way;
        var obj= stack[0].obj;
        for (var prop in obj) 
        {
            if (typeof obj[prop] === 'object') 
            {
                // attributes, which are themselves objects are added to the stack,
                // with their way information.
                stack.push({"way":way.concat(prop),"obj":obj[prop]});
            } 
            else 
            {
                // always start with adding things to the invertedObject,
                var curobj = invertedObject;
                var value = newKey = obj[prop];
                var curpath = way.concat(prop).concat(obj[prop]);

                // for all but the last two path elements the loop below
                // will create the inverted path, starting with the value (obj[prop])
                // as key, Since values need not be unique (as keys), create each 
                // such new key-property as an Array, not to loose inverted pathes.
                while(curpath.length>2)
                {
                    var pathpart = curpath.pop();
                    if(!curobj.hasOwnProperty(pathpart))
                    {
                       curobj[pathpart]=[];
                    }
                    curobj=curobj[pathpart];
                }

                // the last two curpath Array members represent the last key and the 
                // new to be added value. 
                var preLastPart = curpath.pop();
                var lastPart = curpath.pop();
                // Again the artifice of an Array is used since
                // the inverted keys are not unique, hence cases in which  
                // 1 key has (>1) values.
                if(!curobj.hasOwnProperty(preLastPart))
                {
                    curobj[preLastPart]=[];
                }
                curobj[preLastPart].push(lastPart);
            }
        }
        stack.shift();
    }
    return invertedObject;    function invertObject(obj) 
{
    var invertedObject = {};
    // make a stack and prime it with the obj
    var stack = [];
    stack.push({"way":[],"obj":obj});

    // while stuff on the stack
    while (stack.length) 
    {
        var way= stack[0].way;
        var obj= stack[0].obj;
        for (var prop in obj) 
        {
            if (typeof obj[prop] === 'object') 
            {
                // attributes, which are themselves objects are added to the stack,
                // with their way information.
                stack.push({"way":way.concat(prop),"obj":obj[prop]});
            } 
            else 
            {
                // always start with adding things to the invertedObject,
                var curobj = invertedObject;
                var value = newKey = obj[prop];
                var curpath = way.concat(prop).concat(obj[prop]);

                // for all but the last two path elements the loop below
                // will create the inverted path, starting with the value (obj[prop])
                // as key, Since values need not be unique (as keys), create each 
                // such new key-property as an Array, not to loose inverted pathes.
                while(curpath.length>2)
                {
                    var pathpart = curpath.pop();
                    if(!curobj.hasOwnProperty(pathpart))
                    {
                       curobj[pathpart]=[];
                    }
                    curobj=curobj[pathpart];
                }

                // the last two curpath Array members represent the last key and the 
                // new to be added value. 
                var preLastPart = curpath.pop();
                var lastPart = curpath.pop();
                // Again the artifice of an Array is used since
                // the inverted keys are not unique, hence cases in which  
                // 1 key has (>1) values.
                if(!curobj.hasOwnProperty(preLastPart))
                {
                    curobj[preLastPart]=[];
                }
                curobj[preLastPart].push(lastPart);
            }
        }
        stack.shift();
    }
    return invertedObject;
}



}

实际上,由于可以在简单和嵌套对象的许多位置找到相等的值,因此结果将是一个对象,其中每个值都是一个数组,原因有两个:

  1. 多个原始对象的键可以具有相同的值,因此(反转后)可以存在多个原始值。 Array可以存储所有这些多个新值,因此可以存储所有信息。

  2. 在嵌套对象中,唯一性使得每个属性都是直接值或子对象,在键的倒置对象中,我们不仅可以找到多个值,还可以找到那里的多个值也是进一步嵌套的对象。 (由于这个原因,幸运的是Javascript数组,作为一个Object,除了它的条目之外还允许附加属性,因此可以同时作为多个值的存储和嵌套中的子键结构。在倒置的对象结构中,这种数组的双重目的,在JSON表示法中难以显示,因为JSON notation does not allow for Arrays with Object Attributes