Valip
Valip

Reputation: 4620

How to find differences between n arrays of objects

I have an array called props that contains n number of arrays with objects and all arrays contain the same number of objects.

Each object has 4 properties : participation_enabled, name, pathing_enabled, id and these properties can have different values in the other arrays for the same property id...

My goal is to find all object properties that are different in the other arrays of objects and store them in another array called diffs.

Let's take the following example:

[
  [
    {participation_enabled:"false", name:"PropEins", pathing_enabled:"true", id:"prop1"}, 
    {participation_enabled:"false", name:"User Status", pathing_enabled:"false", id:"prop2"}, 
    {participation_enabled:"false", name:"Initial ID", pathing_enabled:"false", id:"prop3"}, 
    {participation_enabled:"false", name:"User ID", pathing_enabled:"false", id:"prop4"}, 
    {participation_enabled:"false", name:"Subdomain", pathing_enabled:"false", id:"prop5"}
  ], 
  [
    {participation_enabled:"false", name:"PropEins", pathing_enabled:"false", id:"prop1"}, 
    {participation_enabled:"false", name:"Room", pathing_enabled:"false", id:"prop2"}, 
    {participation_enabled:"false", name:"Phase", pathing_enabled:"false", id:"prop3"}, 
    {participation_enabled:"false", name:"Custom Insight 4", pathing_enabled:"false", id:"prop4"}, 
    {participation_enabled:"false", name:"Subdomain", pathing_enabled:"false", id:"prop5"}
  ], 
  [
    {participation_enabled:"true", name:"PropEins", pathing_enabled:"true", id:"prop1"}, 
    {participation_enabled:"true", name:"User Status", pathing_enabled:"true", id:"prop2"}, 
    {participation_enabled:"true", name:"Trackingcode", pathing_enabled:"true", id:"prop3"}, 
    {participation_enabled:"false", name:"User ID", pathing_enabled:"false", id:"prop4"}, 
    {participation_enabled:"false", name:"Subdomain", pathing_enabled:"false", id:"prop5"}
  ]
]

For the above example the diffs array should contain the following objects:

[
  {id:"prop1", participation_enabled:["false","true"], pathing_enabled:["false","true"], index:0},
  {id:"prop2", participation_enabled:["false","true"], name:["User Status","Room"], participation_enabled:["false","true"], pathing_enabled:["false","true"], index:1},
  {id:"prop3", participation_enabled:["false","true"], name:["Initial ID","Phase","Trackingcode"], participation_enabled:["false","true"], pathing_enabled:["false","true"], index:2},
  {id:"prop4", name:["User ID","Custom Insight 4"], pathing_enabled:["false","true"], index:3}
]

Any advice greatly appreciated.

Upvotes: 0

Views: 60

Answers (3)

VJI
VJI

Reputation: 81

Check below code. May be this is not most optimal way but it solves the problem.

var mainArray = [
  [{
    participation_enabled: "false",
    name: "PropEins",
    pathing_enabled: "true",
    id: "prop1"
  }, {
    participation_enabled: "false",
    name: "User Status",
    pathing_enabled: "false",
    id: "prop2"
  }, {
    participation_enabled: "false",
    name: "Initial ID",
    pathing_enabled: "false",
    id: "prop3"
  }, {
    participation_enabled: "false",
    name: "User ID",
    pathing_enabled: "false",
    id: "prop4"
  }, {
    participation_enabled: "false",
    name: "Subdomain",
    pathing_enabled: "false",
    id: "prop5"
  }],
  [{
    participation_enabled: "false",
    name: "PropEins",
    pathing_enabled: "false",
    id: "prop1"
  }, {
    participation_enabled: "false",
    name: "Room",
    pathing_enabled: "false",
    id: "prop2"
  }, {
    participation_enabled: "false",
    name: "Phase",
    pathing_enabled: "false",
    id: "prop3"
  }, {
    participation_enabled: "false",
    name: "Custom Insight 4",
    pathing_enabled: "false",
    id: "prop4"
  }, {
    participation_enabled: "false",
    name: "Subdomain",
    pathing_enabled: "false",
    id: "prop5"
  }],
  [{
    participation_enabled: "true",
    name: "PropEins",
    pathing_enabled: "true",
    id: "prop1"
  }, {
    participation_enabled: "true",
    name: "User Status",
    pathing_enabled: "true",
    id: "prop2"
  }, {
    participation_enabled: "true",
    name: "Trackingcode",
    pathing_enabled: "true",
    id: "prop3"
  }, {
    participation_enabled: "false",
    name: "User ID",
    pathing_enabled: "false",
    id: "prop4"
  }, {
    participation_enabled: "false",
    name: "Subdomain",
    pathing_enabled: "false",
    id: "prop5"
  }]
];

var resultArray = mainArray[0];
for (var i = 0; i < mainArray.length; i++) {
  var arrayTocheck = mainArray[i];
  for (var outer = 0; outer < resultArray.length; outer++) {
    row = resultArray[outer];
    if (i == 0) {
      row.participation_enabled = [];
      row.name = [];
      row.pathing_enabled = [];
    }
    for (var inner = 0; inner < resultArray.length; inner++) {
      var rowtoCheck = arrayTocheck[inner];
      if (row.id == rowtoCheck.id) {
        if (!row.participation_enabled.includes(rowtoCheck.participation_enabled) && rowtoCheck.participation_enabled != "") {

          row.participation_enabled.push(rowtoCheck.participation_enabled);
        }
        if (!row.name.includes(rowtoCheck.name) && rowtoCheck.name != "") {
          row.name.push(rowtoCheck.name);
        }
        if (!row.pathing_enabled.includes(rowtoCheck.pathing_enabled) && rowtoCheck.pathing_enabled != "") {
          row.pathing_enabled.push(rowtoCheck.pathing_enabled);
        }
        break;
      }
    }
    resultArray[outer] = row;
  }


}
console.log(resultArray);

Upvotes: 0

user3297291
user3297291

Reputation: 23382

A pure js example. Note that if you can be sure all properties contain strings, you could replace the indexOf search with a object-property based approach to check for duplicates faster.

Important assumption:

  • An object's index in the array determines matching objects

var sampleData = [
  [
    {participation_enabled:"false", name:"PropEins", pathing_enabled:"true", id:"prop1"}, 
    {participation_enabled:"false", name:"User Status", pathing_enabled:"false", id:"prop2"}, 
    {participation_enabled:"false", name:"Initial ID", pathing_enabled:"false", id:"prop3"}, 
    {participation_enabled:"false", name:"User ID", pathing_enabled:"false", id:"prop4"}, 
    {participation_enabled:"false", name:"Subdomain", pathing_enabled:"false", id:"prop5"}
  ], 
  [
    {participation_enabled:"false", name:"PropEins", pathing_enabled:"false", id:"prop1"}, 
    {participation_enabled:"false", name:"Room", pathing_enabled:"false", id:"prop2"}, 
    {participation_enabled:"false", name:"Phase", pathing_enabled:"false", id:"prop3"}, 
    {participation_enabled:"false", name:"Custom Insight 4", pathing_enabled:"false", id:"prop4"}, 
    {participation_enabled:"false", name:"Subdomain", pathing_enabled:"false", id:"prop5"}
  ], 
  [
    {participation_enabled:"true", name:"PropEins", pathing_enabled:"true", id:"prop1"}, 
    {participation_enabled:"true", name:"User Status", pathing_enabled:"true", id:"prop2"}, 
    {participation_enabled:"true", name:"Trackingcode", pathing_enabled:"true", id:"prop3"}, 
    {participation_enabled:"false", name:"User ID", pathing_enabled:"false", id:"prop4"}, 
    {participation_enabled:"false", name:"Subdomain", pathing_enabled:"false", id:"prop5"}
  ]
];

// Reduce an array of data arrays into one array of merged objects
function dataReducer (matches, current) {
  current.forEach(function(obj, i) {
    if (!matches[i]) {
      matches[i] = obj;
    } else {
      matches[i] = mergeObj(matches[i], obj);
    }
  });
  
  return matches;
};

// Merge two matching objects
function mergeObj(obj1, obj2) {
  Object.keys(obj1).forEach(function(key) {
    if (obj1[key] !== obj2[key]) {
      obj1[key] = [].concat(obj1[key]);
      
      if (obj1[key].indexOf(obj2[key]) == -1) {
        obj1[key].push(obj2[key]);
      }
    }
  });
  
  return obj1;
};

var result = sampleData.reduce(dataReducer, []);
console.log(result);

Upvotes: 0

Mykola Borysyuk
Mykola Borysyuk

Reputation: 3411

Not the most elegant way. But it works using underscore JS.

Hope this will helps you. Also add some error handling would be good idea.

EDIT Add support to use google underscore methods. Now all should work. https://sites.google.com/site/scriptsexamples/custom-methods/underscoregs#TOC-_values-Object-obj-

var a = [
  [
    {participation_enabled:"false", name:"PropEins", pathing_enabled:"true", id:"prop1"}, 
    {participation_enabled:"false", name:"User Status", pathing_enabled:"false", id:"prop2"}, 
    {participation_enabled:"false", name:"Initial ID", pathing_enabled:"false", id:"prop3"}, 
    {participation_enabled:"false", name:"User ID", pathing_enabled:"false", id:"prop4"}, 
    {participation_enabled:"false", name:"Subdomain", pathing_enabled:"false", id:"prop5"}
  ], 
  [
    {participation_enabled:"false", name:"PropEins", pathing_enabled:"false", id:"prop1"}, 
    {participation_enabled:"false", name:"Room", pathing_enabled:"false", id:"prop2"}, 
    {participation_enabled:"false", name:"Phase", pathing_enabled:"false", id:"prop3"}, 
    {participation_enabled:"false", name:"Custom Insight 4", pathing_enabled:"false", id:"prop4"}, 
    {participation_enabled:"false", name:"Subdomain", pathing_enabled:"false", id:"prop5"}
  ], 
  [
    {participation_enabled:"true", name:"PropEins", pathing_enabled:"true", id:"prop1"}, 
    {participation_enabled:"true", name:"User Status", pathing_enabled:"true", id:"prop2"}, 
    {participation_enabled:"true", name:"Trackingcode", pathing_enabled:"true", id:"prop3"}, 
    {participation_enabled:"false", name:"User ID", pathing_enabled:"false", id:"prop4"}, 
    {participation_enabled:"false", name:"Subdomain", pathing_enabled:"false", id:"prop5"}
  ]
];
var diff = {};
a.forEach(function(val, i){
  //first just init start object
  if (i == 0) {
    val.forEach(function(v1, ind){
      diff[v1.id] = {};
      diff[v1.id].index = [ind];
      for (var key in v1) {
        diff[v1.id][key] = [v1[key]];
      }
    });
  }
  else {
    //for all other values add them into array and remove dups
    val.forEach(function(v1){
      var id = v1.id;
      for (var key in v1) {
        diff[id][key].push(v1[key]);
      }
    });
  }
});

//now finalize data removing all that have only unique values
for (var key in diff) {
  var nested = diff[key];
  var index = nested.index.pop();
  for (nestedKey in nested) {
    nested[nestedKey] =  _.filter(nested[nestedKey], function(item, pos) {
      return nested[nestedKey].indexOf(item) == pos;
    });
    
    if (nested[nestedKey].length < 2) {delete nested[nestedKey];}
    
  }
  diff[key].id = key;
  diff[key].index = index
  if (_.keys(diff[key]).length < 3) {delete diff[key];}
}

diff = _.values(diff);

console.log(diff);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

Upvotes: 1

Related Questions