D_REIS D_REIS - 6 months ago 13
Javascript Question

Eliminate equal objects and increment the innermost property by 1, based on the number of equal objects

I have the following code that eliminates equal objects in an array, and also increment the innermost property to the number of equal objects:



let SUPER = [{
"NAME1": {
"12": {
"10": 1
}
}
}, {
"NAME1": {
"12": {
"10": 1
}
}
}, {
"NAME1": {
"12": {
"10": 1
}
}
}, {
"NAME1": {
"12": {
"10": 1
}
}
}, {
"NAME1": {
"12": {
"11": 1
}
}
}],
FINAL = [];

for (let _super of SUPER) {
_super = JSON.stringify(_super);
let ii = 1,
ll = SUPER.length,
number = 1;

for (ii; ii < ll; ii++) {
let current = JSON.stringify(SUPER[ii]);
if (_super === current) {
SUPER.splice(ii, 1);
ii--;
number++;
}
}

if (number) {
FINAL.push(function clone(destination, source) {
destination = destination || {};
for (var prop in source) {
typeof source[prop] === 'object' && source[prop] !== null && source[prop] ? destination[prop] = clone({}, source[prop]) : destination[prop] = number;
}
return destination;
}({}, JSON.parse(_super)));
}
}

document.body.innerHTML = JSON.stringify(FINAL, null, 4);





And is almost working, if wasn't for the wrong result when there are two objects or more. The result should be:

[{
"NAME1": {
"12": {
"10": 4
}
}
}, {
"NAME1": {
"12": {
"11": 1
}
}
}]


Not:

[{
"NAME1": {
"12": {
"10": 4
}
}
}, {
"NAME1": {
"12": {
"11": 2
}
}
}]


Any ideas why?

The data given is example data. I don't know the actual properties of all the objects.

Answer

Problems:

  • it was adding 1 in all iterations except for the first one
  • using "for (let _super of SUPER) {" when SUPER was losing items

I've tested with more 'unique' elements. If you run the code below you'll see the correct result.

var SUPER = [
    { "NAME1": { "12": { "21": 1 } } }, 
	{ "NAME1": { "12": { "21": 1 } } }, 
	{ "NAME1": { "12": { "10": 1 } } }, 
	{ "NAME1": { "12": { "10": 1 } } }, 
	{ "NAME1": { "12": { "10": 1 } } }, 
	{ "NAME1": { "12": { "10": 1 } } }, 
	{ "NAME1": { "12": { "10": 1 } } },
	{ "NAME1": { "12": { "12": 1 } } }, 
	{ "NAME1": { "12": { "11": 1 } } }, 
	{ "NAME1": { "12": { "11": 1 } } }],
	FINAL = [];

var firstPass = true;

for (var i = 0; i < SUPER.length; i++) {
  _super = JSON.stringify(SUPER[i]);
  let ii = 1,
    ll = SUPER.length,
    number = 1;

  for (ii; ii < ll; ii++) {
    let current = JSON.stringify(SUPER[ii]);
    if (_super === current) {
      SUPER.splice(ii, 1);
      ii--;
      number++;
    }
  }

  if (number) {
    FINAL.push(function clone(destination, source) {
      destination = destination || {};
      for (var prop in source) {
        typeof source[prop] === 'object' && source[prop] !== null && source[prop] ? destination[prop] = clone({}, source[prop]) : (firstPass) ? destination[prop] = number : destination[prop] = number -1;
      }
      firstPass = false;
      return destination;
    }({}, JSON.parse(_super)));
  }
 
  if (SUPER.length > 0 && SUPER.length <= i) {
     i = 0;
  }
}

document.body.innerHTML = JSON.stringify(FINAL, null, 4);

Output:

[ { "NAME1": { "12": { "21": 2 } } }, { "NAME1": { "12": { "10": 5 } } }, { "NAME1": { "12": { "11": 2 } } }, { "NAME1": { "12": { "12": 1 } } } ]

What's new? (comparing with your code)

  • firstPass declaration as true
  • decrement 1 from number at "typeof source[prop] === 'object' && source[prop] !== null && source[prop] ? destination[prop] = clone({}, source[prop]) : (firstPass) ? destination[prop] = number : destination[prop] = number -1;"
  • set firstPass to false
  • 'for' using index i instead of letting JS iterate through SUPER (since we remove elements from SUPER) by its own
  • reset 'i' to zero if i > SUPER.length

note: you can fix it in many different ways, that's just one of them ;)

ps: despite the code is working, I still don't know the root cause of your problem with "number" =/ so, I consider "(firstPass) ? destination[prop] = number : destination[prop] = number - 1" being a workaround rather than the real fix.

Comments