在唯一的键值对组合上合并对象

时间:2015-03-10 20:04:19

标签: javascript arrays json data-structures underscore.js

我想要一个功能

combineListOnKeys(listOfObjs, listOfKeys) 

将采取这个:

var listOfObjs = 
[
  { name: john, state: ny, age: 12}
, { name: john, state: ny, age: 22}
, { name: john, state: dc, age: 32}
, { name: john, state: dc, age: 42}
, { name: paul, state: ca, age: 52}
]

var listOfKeys = ["name", "state"]

并返回:

combineListOnKeys(listOfObjs, listOfKeys)
[ 
 { "name": john, "state": ny, "age": [12, 22]}
,{ "name": john, "state": dc, "age": [32, 42]}
,{ "name": paul, "state": ca, "age": [52]} 
]

我基本上希望匹配所有这些对象共享的多个指定键,并获取剩余的未指定键并将它们组合到一个列表中,从而删除一些重复信息。

我使用的是underscore.js,但我在文档中找不到此问题的示例。提前谢谢!

2 个答案:

答案 0 :(得分:1)

很抱歉,这并不符合您修改后的功能要求,但是在您修改并投入大量精力之前我已经开始了,我希望这足以让您将自己的功能整合在一起。连续使用下划线的_.reduce和_.each方法(并且_.each可以替换为第二个_.reduce,或者使用_.map - 像往常一样,不止一个这样做的方法)。

var arr = [
  { name: 'john', state: 'ny', age: 12}
, { name: 'john', state: 'ny', age: 22}
, { name: 'john', state: 'dc', age: 32}
, { name: 'john', state: 'dc', age: 42}
, { name: 'paul', state: 'ca', age: 52}
];

var resultsMap = _.reduce(arr, function(memo, arrEl) {
    /*
     * var key = JSON.stringify(_.omit(arrEl, 'age'));
     *
     * From original answer but naively fails to account for Javascript objects not returning in order.
     * See "IIFE" below and http://stackoverflow.com/a/28989092/34806
     */ 
    var key = (function() {
        var ageOmittedObj = _.omit(arrEl, 'age');
        var ageOmittedPairs = _.pairs(ageOmittedObj);

        var sortedPairs = _.reduce(_.keys(ageOmittedObj).sort(), function(sortedPairs, key) {
            var pair = _.find(ageOmittedPairs, function(kvPair) {return kvPair[0] == key});
            sortedPairs.push(pair);
            return sortedPairs;
        }, []);

        return JSON.stringify(sortedPairs)
    }) ();

    memo[key] = memo[key] || {};
    memo[key].ages = memo[key].ages || [];
    memo[key].ages.push(arrEl.age);

    return memo;
}, {});


var resultsArr = [];

_.each(resultsMap, function(v, k) {
    var resultObj = {};
    var nameStatePairs = JSON.parse(k);
    var nameStateObj = _.object(_.map(nameStatePairs, function(pair){return [pair[0], pair[1]]}));
    // compare above to http://stackoverflow.com/a/17802471/34806

    resultObj.name = nameStateObj.name;
    resultObj.state = nameStateObj.state;
    resultObj.age = v.ages;
    resultsArr.push(resultObj);
});

console.log(JSON.stringify(resultsArr));
// [{"name":"john","state":"ny","age":[12,22]},{"name":"john","state":"dc","age":[32,42]},{"name":"paul","state":"ca","age":[52]}]

答案 1 :(得分:0)

不在 underscore.js 中,而是普通的JS。哪个应该可以正常工作,因为下划线是一个运行在JavaScript上的库。

我将使用array.prototype.map输出一个新数组,并结合使用for循环测试新数组的倍数。由于这只是一个深度,我们不需要递归。



var arr = [
  { name: "john", state: "ny", age: 12}
, { name: "john", state: "ny", age: 22}
, { name: "john", state: "dc", age: 32}
, { name: "john", state: "dc", age: 42}
, { name: "paul", state: "ca", age: 52}
]

var arr2d2 = []; //new array that is going to contain the merged values.
arr.map(function(element){
    var outerElement = element;
    var found = false; //set initially to false. If not found add element to the new array.
    for (var i = 0; i < arr2d2.length; i++)
    {
        if (arr2d2[i].name == outerElement.name && arr2d2[i].state == outerElement.state)
        {
           found = arr2d2[i]; // save the element.
           break; //stop the loop
        }
    };
    if (found)
    {
       if (found.age != outerElement.age)
       {
          
          found.age.push(outerElement.age); //push the age to the new value.
       }
    }
    else
    {
      outerElement.age = [outerElement.age]; //convert age to an array, like you specified.
      arr2d2.push(outerElement); //not found yet. push element;
    }  
 
});

document.body.innerHTML += JSON.stringify(arr2d2); //only to display the result. Not part of the solution.
&#13;
&#13;
&#13;