neowenshun
neowenshun

Reputation: 960

How to compare the difference in javascript array dynamically

I have a react update form and i wish to differentiate the form data and the current data to figure out what has changed dynamically.

Problem summarized

find the minimum differences between 2 nested objects. And output an array of changed properties paths. E.g. if department_id in the departments list at index 0 changes while the rest stays the same - the algorithm should output ['departments'].

Example Data:

My data usually comes in like this (This is a simplified form , but the data has varying depths as shown here):

{id:115,
 departments: [{
              department_id:1,
              department_name:"asd"}],
 name: 'Test project',

}

Lets say the user decides to add in a department to the object, i wish to be able to detect the changes this way:

changes = ['departments']

or if the user changes the name :

changes = ['name']

the additional challenge here is that i wish to use this function across my forms , which means that the comparing should be able to handle different keys and depths of data

Edit:

data1 :

creation_date: "2020-06-16"
customer_information: Array(1)
                     0: 1
project_status: 1
sales_department: 1
sales_project_name: "helloss2sasdssssssssssss"
userProfile: Array(2)
             0: 1

data2:

creation_date: "2020-06-16"
customer_information: Array(1)
                      0: 1

project_status: 1
sales_department: 1
sales_project_name: "helloss2"
userProfile: Array(2)
             0: 1
             1: 2

Function called here :

const data1 = action.original
const data2 = action.final
const difference = Object.keys(data1).filter((key)=>!walk(data1[key],data2[key]))
console.log(difference)

Here is the console log for difference :

[] 

Expected:

['userProfile' , 'sales_project_name']

Upvotes: 1

Views: 982

Answers (2)

user120242
user120242

Reputation: 15268

Simple naive recursive function walk that deep equals and returns if the branch has changes. filters keys that match.

data1 = {
  creation_date: "2020-06-16",
  customer_information: [1],
  project_status: 1,
  sales_department: 1,
  sales_project_name: "helloss2sasdssssssssssss",
  userProfile: [1],
  version: 1
}
data2 = {

  creation_date: "2020-06-16",
  customer_information: [1],

  project_status: 1,
  sales_department: 1,
  sales_project_name: "helloss2",
  userProfile: [1, 2],
  version: 2
}

walk = (node1, node2) => {
  // different types, return false
  if (typeof node1 !== typeof node2) return false
  if (node1 && node2 && typeof node1 === 'object') {
    const keys = Object.keys(node1)
    // if type object, check same number of keys and walk on node1, node2
    return keys.length === Object.keys(node2).length &&
      keys.every(k => walk(node1[k], node2[k]))
  }
  // not object and types are same, return if node1 is equal to node2
  return node1 === node2
}
console.log(
  Object.keys(data1).filter((key) => !walk(data1[key], data2[key]))
)

Upvotes: 2

Matthias S
Matthias S

Reputation: 3553

If you don't want to use any library for comparing nested objects, you could simply convert to JSON and compare the strings.

Assuming you want to compare objects, it could look like this:

function getUnequalKeys(object1, object2) {
  let unequalKeys = [];
  for (let key in object1) {
    if (object1.hasOwnProperty(key) 
        && (
         !object2.hasOwnProperty(key)
         || JSON.stringify(object1[key]) !== JSON.stringify(object2[key])
        )
    ) {
      unequalKeys.push(key);
    }
  }
  for (let key2 in object2) {
    if (object2.hasOwnProperty(key2) && !object1.hasOwnProperty(key2)) {
      unequalKeys.push(key2);
    }
  }
  return unequalKeys;
}

This would return all first-level keys that don't exist in both objects or have different values.

EDIT: What it essentially does is the following: Loop through each key in object1. Check if that same key exists in object2. If it does not exist, it means the key is not equal, so the condition is true and the key is added to the list of unequal keys. If the key does exist in object2, make a JSON string of both values and compare those strings. If the strings are not the same, it means they have different values. In that case, also add the key to the array of unequal keys. Now we already checked all keys of object1.

As a last step, go through all keys of object2 and check if they are not present in object1, and in that case also add them to the array of unequal keys.

Upvotes: 0

Related Questions