Reputation: 5192
In my node app i have to construct an object array from another object array.
Consider my object array as...
levels: [
{
country_id: 356,
country_name: "aaa",
level0: "bbbb",
level1: "cccc",
level2: "dddd",
level3: "eeee",
level4: "fffff"
},
{
country_id: 356,
country_name: "aaaa",
level0: "bbbb",
level1: "cccc",
level2: "dddd",
level3: "eeee",
level4: "gggg"-----------> here is the differnce..
}
]
If for same id any 1 of the above is different i have to make it an array and should be single entry for 1 id.
so what i want is:
levels: [
"356":{
country_name: "aaa",
level0: "bbbb",
level1: "cccc",
level2: "dddd",
level3: "eeee",
level4: ["fffff","gggg"]
}]
But i cant get the right way to do it.Please help me to solve this.Thanks in advance.
Upvotes: 3
Views: 83
Reputation: 239443
Note: Please note that, this program assumes that there are only two repetitions in the levels.
var obj = {
levels: [{
country_id: 356,
country_name: "aaa",
level0: "bbbb",
level1: "cccc",
level2: "dddd",
level3: "eeee",
level4: "fffff"
}, {
country_id: 356,
country_name: "aaa",
level0: "bbbb",
level1: "cccc",
level2: "dddd",
level3: "eeee",
level4: "gggg"
}]
};
obj.levels = obj.levels.reduce(function(result, current) {
result[current.country_id] = result[current.country_id] || {};
var temp_result = result[current.country_id];
for (var key in current) {
if (temp_result.hasOwnProperty(key) === false) {
temp_result[key] = current[key];
} else if (temp_result[key] !== current[key]) {
temp_result[key] = [temp_result[key], current[key]];
}
}
return result;
}, {})
console.log(obj);
Output
{ levels:
{ '356':
{ country_id: 356,
country_name: 'aaa',
level0: 'bbbb',
level1: 'cccc',
level2: 'dddd',
level3: 'eeee',
level4: ['fffff', 'gggg'] } } }
And this is a generic solution,
obj.levels = obj.levels.reduce(function(result, current) {
result[current.country_id] = result[current.country_id] || {};
var temp_result = result[current.country_id],
toString = Object.prototype.toString;
for (var key in current) {
if (temp_result.hasOwnProperty(key) === false) {
temp_result[key] = current[key];
} else if (toString.call(temp_result[key]) === "[object Array]") {
if (temp_result[key].every(function(currentItem) {
return currentItem !== current[key];
})) {
temp_result[key].push(current[key]);
}
} else if (temp_result[key] !== current[key]) {
temp_result[key] = [temp_result[key], current[key]];
}
}
return result;
}, {});
Upvotes: 2
Reputation: 20394
Looks like you already accepted an answer but I'll post mine as well. It has the following advantages:
Here is the code:
var levels = [
{
country_id: 356,
country_name: "aaa",
level0: "bbbb",
level1: "cccc",
level2: "dddd",
level3: "eeee",
level4: "fffff"
},
{
country_id: 356,
country_name: "aaaa",
level0: "bbbb",
level1: "cccc",
level2: "dddd",
level3: "eeee",
level4: "gggg"
},
{
country_id: 356,
country_name: "aaaa",
level0: "bbbb",
level1: "cccd",
level2: "dddd",
level3: "eeee",
level4: "gggg"
},
{
country_id: 354,
country_name: "aaaa",
level0: "bbbb",
level1: "cccc",
level2: "dddd",
level3: "eeee",
level4: "gggg"
}
];
var mergedLevels = {};
function shallowCopyWithoutId(object) {
var o = {},
i;
for (i in object) {
if (object.hasOwnProperty(i) && i !== 'country_id') {
o[i] = object[i];
}
}
return o;
}
function merge(o1, o2) {
var i;
for (i in o1) {
if (o1.hasOwnProperty(i) && o2.hasOwnProperty(i)) {
if (o1[i] instanceof Array) {
if (o1[i].indexOf(o2[i]) === -1) o1[i].push(o2[i]);
} else if (o1[i] !== o2[i]) {
o1[i] = [o1[i], o2[i]];
}
}
}
}
var i, level;
for (i = 0; i < levels.length; i++) {
level = levels[i];
if (!mergedLevels.hasOwnProperty(level.country_id)) {
mergedLevels[level.country_id] = shallowCopyWithoutId(level);
} else {
merge(mergedLevels[level.country_id], level);
}
}
console.log(mergedLevels);
Output:
{ '354':
{ country_name: 'aaaa',
level0: 'bbbb',
level1: 'cccc',
level2: 'dddd',
level3: 'eeee',
level4: 'gggg' },
'356':
{ country_name: [ 'aaa', 'aaaa' ],
level0: 'bbbb',
level1: [ 'cccc', 'cccd' ],
level2: 'dddd',
level3: 'eeee',
level4: [ 'fffff', 'gggg' ] } }
Upvotes: 1
Reputation: 13702
In the following example I use underscore js
var obj = {
levels: [
{
country_id: 356,
country_name: "aaa",
level0: "bbbb",
level1: "cccc",
level2: "dddd",
level3: "eeee",
level4: "fffff"
},
{
country_id: 356,
country_name: "aaaa",
level0: "bbbb",
level1: "cccc",
level2: "dddd",
level3: "eeee",
level4: "gggg"
}]
};
var transform = function (obj) {
// a temporary object so we can do lookups more quicker
var tmpObj = {};
// merge two elements as described in Question
var merge = function (dst, src) {
_.each(src, function (val, key) {
if (key.indexOf('level') === -1) { // merge only level keys
return;
}
var dstVal = dst[key];
if (!dstVal) { // key & val are not in the dst object
dst[key] = val;
} else if (dstVal !== val && !_.isArray(dstVal)) { // key is present but values differ
dst[key] = [dstVal, val];
} else if (_.isArray(dstVal) && _.indexOf(dstVal, val) === -1) { // key is present and the val is not in the array
dst[key].push(val);
}
});
};
// iterate through all the elements and merge them
_.each(obj.levels, function (el) {
var obj = tmpObj[el.country_id];
if (obj) {
merge(obj, el);
} else {
tmpObj[el.country_id] = el;
}
});
// map the elements back
obj.levels = _.map(tmpObj, function (el) { return el; });
};
transform(obj);
var resultObj = _.map(tmpObj, function (el) { return el; }); // the tmp object is transformed back to the desired format
Output:
Upvotes: 1