3

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.

1
  • Please stop making trivial edits to your posts to "bump" them. If you keep doing this, we will lock your posts from further editing. Commented Apr 9, 2014 at 20:09

3 Answers 3

2

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;
}, {});
Sign up to request clarification or add additional context in comments.

2 Comments

once again you saved me..Thanks a lot..+1 for your help.. I like your approach to solve the problem.. Do you have any link for node.js which could start from the beginning(whether i could first should be an comfort level in javascript) so that i can master node.js.. As i said i am new to java script.. giude me to become comfortable with node.js..
@Subburaj Actually I learnt everything from Stackoverflow only :)
1

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:

enter image description here

Comments

1

Looks like you already accepted an answer but I'll post mine as well. It has the following advantages:

  1. It preserves the original level objects by creating shallow copies of them.
  2. It intersects objects with the same key and doesn't add duplicate values.

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' ] } }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.