转换键 - 值对的数组:值的键和唯一键的值

时间:2015-05-30 00:08:51

标签: javascript arrays key-value

我想转换一个充当键值存储的数组数组。

每个子数组采用以下形式:self.IMG_MAPPING,其中['tom',['hello','world']]索引([0])是'key','tom'索引(数组)是'价值'。

我希望我的数组中的所有'values'都是新数组的唯一键,并且我的数组中的键应该构造包含所有以前保存相应值的键的新子数组。

例如:

[1]

以上输入应达到以下输出:

var myArray = [
    ['tom',['hello','world']],
    ['bob',['world','foo']],
    ['jim',['foo','bar']]
];

我该如何做到这一点?

3 个答案:

答案 0 :(得分:2)

在进入“解决方案”之前,我想解决这个存储和描述数据非常糟糕的事实。如果您正在寻找类似于PHP的关联数组的内容,您应该学习如何work with objects

JS中的对象只是唯一键(属性)的集合 - >价值对。

作为对象,您的数据集如下所示:

var before = {
  tom: ['hello','world'],
  dick: ['world','foo'],
  harry: ['foo','bar']
};

var after = {
  bar: ["harry"],
  foo: ["dick", "harry"],
  hello: ["tom"],
  world: ["tom", "dick"]
};

这是使用对象的实现。也很天真,但更简单。

DEMO

var before = {
  tom: ['hello','world'],
  dick: ['world','foo'],
  harry: ['foo','bar']
};

var after = {
  bar: ["harry"],
  foo: ["dick", "harry"],
  hello: ["tom"],
  world: ["tom", "dick"]
};


function resObj(obj) {
  var o = {};
  
  for (var k in obj) {
    for (var i = 0; i < obj[k].length; i++) {
      o[obj[k][i]] = o[obj[k][i]] || [];
      o[obj[k][i]].push(k);
    }
  }
  
  return o;
}

console.log('Expected:', after);
console.log('Actual:', resObj(before));

下面是如何使用数组执行所需操作的示例。这是天真的,缓慢的,我确信它可以改进,但这与我的回答有关。

粗略的演示。请注意,我们使用一个对象作为交换,使其几乎与上面相同。

DEMO

var inp = [
    ['tom',['hello','world']],
    ['dick',['world','foo']],
    ['harry',['foo','bar']]
];

var out = [
    ['hello',['tom']],
    ['world',['tom','dick']],
    ['foo',['dick','harry']],
    ['bar',['harry']]
];

function resArray(arr) {
  var q = {},
      o = [];
  
  for(var i = 0; i < arr.length; i++) {
    for (var j = 0; j < arr[i][1].length; j++) {
      q[arr[i][1][j]] = q[arr[i][1][j]] || [];
      q[arr[i][1][j]].push(arr[i][0]);
    }
  }
  
  for (var m in q) {
    o.push([m, q[m]]);
  }
  
  return o;
}

console.log('Expected:', out);
console.log('Actual:', resArray(inp));

答案 1 :(得分:2)

就像我在评论中所说,你基本上要求计算多对一关系的倒数。您可以将关系视为来自一对对象的映射。从逻辑上讲,你正在映射&#34; tom&#34;到&#34;你好&#34;和&#34;世界&#34;。反向关系将映射&#34;你好&#34;和#34;世界&#34;到&#34;汤姆&#34;。

当你想到&#34;关系&#34;时,你应该考虑关联容器而不是数组。除非你的密钥是密集的整数,否则使用数组会使你的算法效率低下。

这会产生正确的输出:

&#13;
&#13;
var myRelation = [
  ['tom', ['hello', 'world']],
  ['dick', ['world', 'foo']],
  ['harry', ['foo', 'bar']]
];

function inverse(relation) {
  // This first half does the hard work of computing the inverse.
  var intermediate = {};
  relation.forEach(function(outerEntry) {
    outerEntry[1].forEach(function(innerEntry) {
      if (!intermediate[innerEntry]) {
        intermediate[innerEntry] = {};
      }
      intermediate[innerEntry][outerEntry[0]] = true;
    });
  });
  // This second half turns the intermediate assocative container
  // back into an array of nested arrays.
  var output = [];
  Object.keys(intermediate).forEach(function(outerEntry) {
    output.push([outerEntry, []]);
    Object.keys(intermediate[outerEntry]).forEach(function(innerEntry) {
      output[output.length - 1][1].push(innerEntry);
    });
  });
  return output;
}

console.log(inverse(myRelation));
&#13;
&#13;
&#13;

如果您不需要在数组中重现原始输出格式,问题会变得更简单。

答案 2 :(得分:1)

这是一个干净的转换功能实现。

/**
 * Converts from a one-to-many to many-to-one relationship.
 * @param  {[array]} pairs [array representing a one-to-many relationship.]
 * @return {[array]}       [array representing the same data, in a many-to-one relationship]
 */
var oneToManyFlip = function(pairs){
  //Recall that current[0] is our 'key'.
  //Also recall that 'prev' is the empty object we passed in.
  var result = pairs.reduce(function(storage, current, index, array){ 
    current[1].forEach(function(element, index){
      if(storage[element] === undefined){ storage[element] = [];}
      storage[element].push(current[0]);
    });
    return storage;
  }, {});
  return Object.keys(result).map(function(element){
      return [element, result[element]];
    });
}

我希望它有点清洁,易于推理。地图&amp;减少起初可能有点棘手。

您可以了解有关功能性JS here的更多信息。它对迭代的这些计算很有用。