Search code examples
javascriptperformancejavascript-objects

How to detect object differences between two arrays?


I'm trying to compare two arrays of objects and returns a list of updated objects. I don't want to use lodash just the javascript data structures and functions.

E.g:

I have a first array which named arr1 = [
{
    name: 'attribute 1',
    id: 12,
    value: 40,
    docs:[],
    version: 1,
},
{
    name: 'attribute 41',
    id: 12,
    value: 6,
    version: 1,
}
]

And another array:

array2 =  [
    {
        name: 'attribute 1',
        attributeTypeId: 12,
        value: 65,
        docs: ['bla bla']
    }
]

I'm trying to iterate through the two arrays and detect the differences and returns an array like that:

result = [
{
    name: 'attribute 1',
    id: 12,
    value: 65,
    docs:['bla bla'],
    version: 1,
},
{
    name: 'attribute 41',
    id: 12,
    value: 6,
    version: 1,
}]

I wrote some uncomplete function (not optimized yet just a brute force solution):

const filterProperties = (e) => {
    return e.toLowerCase() !== 'name' && e.toLowerCase() !== 'id' 
}

// function sort

const sortProperties = (a, b) => a < b ? -1 : 1;

let result = []
attributesUpdate.forEach(attr => {
    const attrProps = Object.getOwnPropertyNames(attr);

    // iterate the attributes
    for (let i = 0; i < attributes.length; i++) {
        let attribute = attributes[i];
        // check if the attribute to update has a different name or attributeTypeId
        if (attribute.name !== attr.name) {
                result = result.concat(attr);

        }

        // check if the attribute to update has the same name, id
        // of the originalOne
        if (attribute.name === attr.name && attribute.id=== attr.id) {
            let obj = {
                name: attribute.name,
                id: attribute.id,
            }
            // get the properties of the attribute
            const attributeProps = Object.getOwnPropertyNames(attribute);

            // extract the name and id from the list
            const filtredAttributeProps = attributeProps.filter(filterProperties);
            const filteredattrProps = attrProps.filter(filterProperties);


            // returns the length of each array of properties
            const attrLength = filteredattrProps.length;
            const attributeLength = filtredAttributeProps.length;

            if (attrLength === attributeLength) {
                for (let j = 0; j < attrLength; j++) {
                    const propName = filteredattrProps[j];
                    obj[propName] = attr[propName];
                }

                result = result.filter(e => e.name === attr.name 
                    && e.id=== attr.id)
                    .map(e => Object.assign(e, {obj}))
            }

            if (attrLength !== attributeLength) {
                // sort the array of properties
                const sortedAttrProps = filteredattrProps.sort(sortProperties);
                const sortedAttributeProps = filtredAttributeProps.sort(sortProperties);

                // check the shortest object
                const min = attrLength < attributeLength ? attrLength : attributeLength;
                // get the biggest object
                const longestObjProps = attrLength === min ? sortedAttributeProps : sortedAttrProps;
                const longestObj = attrLength === min ? attribute : attr
                const shortestProps = attrLength === min ? sortedAttrProps: sortedAttributeProps;
                const shortestObj = attrLength === min ? attr : attribute

                // fill the object with attr properties
                for(let j = 0; j < min; j++) {
                    const propName = shortestProps[j];
                    obj[propName] = shortestObj[propName];
                }


                // fill the remaining properties in the object
                const remainingProperties = longestObjProps.filter(e => !shortestProps.includes(e));
                for (let j = 0; j < remainingProperties.length; j++) {
                    const propName = remainingProperties[j];
                    obj[propName] = longestObj[propName]
                }

                if (!result.length || result.filter(e => e.name !== attr.name && 
                    e.id!== attr.id).length === 0) {
                        result.concat(obj);
                    }

            }

        }
    }
})

console.log('result: ', result);

I got such a result :

[
{
    name: 'attribute 1',
    attributeTypeId: 12,
    value: 65,
    docs: ['bla bla']
}
]

How can I fix this code to get the desired results? I hope that my question will not be downvoted. Any suggestion will be welcome.


Solution

  • What this code does is loop through the objects in array2, and then when it finds that there is a matching name/id in arr1, it simply updates the properties of that object. If not found, it will add the object to arr1.

    arr1 = [{
        name: 'attribute 1',
        id: 12,
        value: 40,
        docs: [],
        version: 1,
      },
      {
        name: 'attribute 41',
        id: 12,
        value: 6,
        version: 1,
      }
    ];
    
    array2 = [{
      name: 'attribute 1',
      attributeTypeId: 12,
      value: 65,
      docs: ['bla bla']
    }];
    
    updateArray(arr1, array2);
    
    console.log(arr1);
    
    function updateArray(arrayToUpdate, dataToUpdateWith) {
      dataToUpdateWith.forEach(function(obj) {
        var objToUpdate = checkIfNameIdExists(arrayToUpdate, obj.name, obj.attributeTypeId);
        if (objToUpdate === false) {
          objToUpdate = obj;
          arrayToUpdate.push(objToUpdate);
        } else {
          for (var prop in obj) {
            if (objToUpdate.hasOwnProperty(prop)) {
              var nameInFinalObject = prop;
              if (prop === "attributeTypeId") {
                nameInFinalObject = "id";
              }
              objToUpdate[nameInFinalObject] = obj[prop];
            }
          }
        }
    
      });
    }
    
    function checkIfNameIdExists(arrOfObj, name, id) {
      if (name === null) {
        return false;
      }
      var output = false;
      arrOfObj.forEach(function(obj) {
        if (obj.name === name) {
          output = obj;
          return true;
        }
      });
    
      return output;
    }