简体   繁体   中英

Node.js + objectArray

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.

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;
}, {});

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:

在此输入图像描述

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM