I would like a function
我想要一个功能
combineListOnKeys(listOfObjs, listOfKeys)
that will take this:
这将采取这个:
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"]
and returns this:
并返回此:
combineListOnKeys(listOfObjs, listOfKeys)
[
{ "name": john, "state": ny, "age": [12, 22]}
,{ "name": john, "state": dc, "age": [32, 42]}
,{ "name": paul, "state": ca, "age": [52]}
]
I'm essentially looking to match on multiple specified keys that all these objects share, and take the remaining unspecified keys and combine them into a list, thus removing some duplicate information.
我基本上希望匹配所有这些对象共享的多个指定键,并获取剩余的未指定键并将它们组合成一个列表,从而删除一些重复信息。
I'm using underscore.js, but I cannot find an example of this problem in the docs. Thanks in advance!
我正在使用underscore.js,但我在文档中找不到此问题的示例。提前致谢!
2 个解决方案
#1
1
Sorry this doesn't conform with your revised requirements for a function but I got started before you revised and put in a lot of effort and I hope this is enough for you to put together your own function. Using underscore's _.reduce and _.each methods in succession (and the _.each can probably be replaced with a second _.reduce, or with _.map -- as usual there's more than one way to do it).
对不起,这不符合你修改的功能要求,但是在你修改并付出很多努力之前我已经开始了,我希望这足以让你把你自己的功能放在一起。连续使用下划线的_.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://*.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://*.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]}]
#2
0
Not in underscore.js, but plain JS. Which should work fine since underscore is a library running on JavaScript.
不是在underscore.js,而是普通的JS。哪个应该可以正常工作,因为下划线是一个运行在JavaScript上的库。
I would output a new array using array.prototype.map
combined with a for loop that test the new array for multiples. Since this is only one dimension deep, we do not need recursion.
我将使用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.
#1
1
Sorry this doesn't conform with your revised requirements for a function but I got started before you revised and put in a lot of effort and I hope this is enough for you to put together your own function. Using underscore's _.reduce and _.each methods in succession (and the _.each can probably be replaced with a second _.reduce, or with _.map -- as usual there's more than one way to do it).
对不起,这不符合你修改的功能要求,但是在你修改并付出很多努力之前我已经开始了,我希望这足以让你把你自己的功能放在一起。连续使用下划线的_.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://*.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://*.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]}]
#2
0
Not in underscore.js, but plain JS. Which should work fine since underscore is a library running on JavaScript.
不是在underscore.js,而是普通的JS。哪个应该可以正常工作,因为下划线是一个运行在JavaScript上的库。
I would output a new array using array.prototype.map
combined with a for loop that test the new array for multiples. Since this is only one dimension deep, we do not need recursion.
我将使用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.