Differences Between Two Objects

Updated on 28 May, 2025
Differences Between Two Objects header image

Problem Statement

The task is to develop a function capable of evaluating two deeply nested structures, either objects or arrays, referred to here as obj1 and obj2. This function identifies the differences between these structures and outputs a new object that captures these variations succinctly.

The core functionality revolves around:

  • Identifying properties or indices where obj1 and obj2 differ.
  • Generating a return object that consists only of entries where differences exist between obj1 and obj2.
  • Representing each difference for keys as an array in the format $value in obj1, value in obj2$.
  • Avoiding inclusion of keys that appear only in one of the objects for comparison to ensure that only the differences between shared structures are highlighted.

Arrays are processed similarly to objects with the indication that indices serve as keys for comparison. The function leverages the assumption that both input structures are derived from JSON.parse, enabling consistency in handling.

Examples

Input:

obj1 = {"a": 1, "b": {"x": 10, "y": 20}, "c": [1, 2, 3]}
obj2 = {"a": 1, "b": {"x": 15, "y": 20}, "c": [1, 4, 3]}

Output:

{
  "b": {
    "x": [10, 15]
  },
  "c": {
    "1": [2, 4]
  }
}

Explanation:

Only the values of `b.x` and `c[1]` differ between the two objects. Other values are identical and thus excluded.

Constraints

  • obj1 and obj2 are valid objects or arrays parsed from JSON.parse
  • 1 <= total number of keys or indices <= 10^4
  • Nested depth of structures ≤ 100
  • All primitive values are of types: string, number, boolean, or null
  • Arrays only contain serializable elements (objects, arrays, or primitives)
  • Keys present only in one of the objects are ignored during comparison

Approach and Intuition

By examining the provided examples, we can deduce a general workflow for solving the problem:

  1. Initialize an empty object to store the differences called diff.

  2. Recursively compare each corresponding key or index in obj1 and obj2.

  3. For each key:

    • If both obj1 and obj2 have the key, and the values differ:

      • If both values are primitive data types (e.g., string, number), directly compare them.
      • If the values differ in type (object/array vs primitive), capture them as is in the difference array.
      • If both are objects or arrays, recursively apply the comparison to chart sub-differences.
    • Omit keys that appear exclusively in one object to focus solely on modifications rather than additions or deletions.

    • Continue this process recursively for objects within objects or nested arrays.

  4. Ending condition for recursion occurs when all properties have been either matched or the differences have been logged.

  5. Return the diff object containing all the captured differences in the prescribed format.

As observed from the examples:

  • Changes in either type or value are captured.
  • Keys where the value remains unchanged are disregarded to minimize redundancy.
  • Array indices are processed similar to object keys, with alterations within arrays marked according to their depth and index, showcasing granularity in difference mapping.

In essence, the goal is to deliver a structured representation that mirrors the inputs' structure but exclusively highlights their discrepancies.

Solutions

  • JavaScript
js
function compareObjects(firstObject, secondObject) {
    if (firstObject === secondObject) return {};
    if (firstObject === null || secondObject === null) return [firstObject, secondObject];
    if (typeof firstObject !== 'object' || typeof secondObject !== 'object') return [firstObject, secondObject];
    if (Array.isArray(firstObject) !== Array.isArray(secondObject)) return [firstObject, secondObject];

    const differences = {};
    for (const property in firstObject) {
        if (property in secondObject) {
            const diff = compareObjects(firstObject[property], secondObject[property]);
            if (Object.keys(diff).length > 0) {
                differences[property] = diff;
            }
        }
    }
    return differences;
}

This JavaScript function, compareObjects, checks for differences between two input objects and returns an object representing the differences. It follows these steps to achieve this:

  1. Checks if the two objects are exactly the same instance. If true, returns an empty object {} since there are no differences.

  2. Checks if either object is null. If either is null, returns an array containing both objects since comparing a null with any object will generally lead to a difference.

  3. Validates if both variables are indeed objects (not primitives). If either is not an object, returns an array with both variables.

  4. Checks if the type mismatches between objects; specifically, whether one is an array and the other is not. Returns both objects in an array if they differ in type (array vs non-array).

  5. Initializes an empty object differences to collect properties that differ. Iterates over properties of the first object and for each property:

    • Compares properties in both objects recursively by calling compareObjects again.
    • If recursive comparison finds differences (i.e., the returned object has keys), adds these differences to the differences object under the respective property name.
  6. Returns the differences object containing all properties that show variation between the two objects.

This function provides a deep comparison that can navigate through nested structures within objects, making it useful for identifying not just surface-level differences but also those buried within nested objects or arrays.

Comments

No comments yet.