Как обнаружить объектные различия между двумя массивами? - PullRequest
0 голосов
/ 30 ноября 2018

Я пытаюсь сравнить два массива объектов и возвращает список обновленных объектов.Я не хочу использовать lodash только структуры данных и функции javascript.

Например:

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,
}
]

И еще один массив:

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

I 'Я пытаюсь перебрать два массива и обнаружить различия, и возвращает массив, подобный этому:

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

Я написал некоторую незавершенную функцию (не оптимизированную, а просто грубое решение):

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);

Я получил такой результат:

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

Как я могу исправить этот код, чтобы получить желаемые результаты?Я надеюсь, что мой вопрос не будет опущен.Любое предложение будет приветствоваться.

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

Допущения:

  1. Значения в каждом из объектов имеют одинаковый тип, и значения не являются вложенными, поэтому существует необходимость рекурсивного обхода дерева для сравнения равенства и т. Д.

  2. Первый массив является источником, а последующий (с тем же именем ) является мутированной формой.Мы не обрабатываем удаления свойств из исходного объекта.Из того, что указано в ОП, мы учитываем только изменения стоимости.

const d1 = [{ name: 'attribute 1', id: 12, value: 40, docs: [], version: 1, }, { name: 'attribute 41', id: 12, value: 6, version: 1, } ]
const d2 = [{ name: 'attribute 1', attributeTypeId: 12, value: 65, docs: ['bla bla'] }]

const isChanged = (a, b) =>
   Array.isArray(a) ? !a.every(x => b.includes(x)) : a !== b

const compare = (o1, o2) => Object.entries(o1).reduce((r, [k,v]) => {
  if(k in o2 && isChanged(o2[k], v))
     Object.assign(r, {[k]: o2[k]})
  return r
}, o1)

const group = (a, b) => [...a, ...b].reduce((r,c) => 
   (r[c.name] = [...r[c.name] || [], c], r), {})

const result = Object.values(group(d1,d2)).reduce((r,c) => 
   (r.push(c.length == 2 ? compare(...c) : c[0]), r), [])

console.log(result)

Идея состоит в том, чтобы объединить объекты в один массив, сгруппировать их по имени и, если есть какие-либо изменения, groups с length of 2 будет сравниваться с помощью *Функция 1026 *.В противном случае просто добавляется к конечному результату.

0 голосов
/ 30 ноября 2018

Этот код выполняет цикл по объектам в array2, а затем, когда обнаруживает, что в arr1 есть совпадающее имя / идентификатор, он просто обновляет свойства этого объекта.Если объект не найден, он добавит объект к 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...