Объединить соответствующие объекты внутри массива JS - PullRequest
1 голос
/ 28 января 2020

Как я могу объединить два массива объектов, где один объект из одного массива соответствует одному объекту в другом массиве. Объект, который не соответствует, должен быть сохранен. id и uid - соответствующее условие.

const data1 = [{
  id: 1,
  someKey1: 'someValue2'
}, {
  id: 2,
  someKey2: 'someValue2'
}, {
  id: 3,
  someKey3: 'someValue3'
}]
const data2 = [{
  uid: 1,
  someKey4: 'someValue4'
}, {
  uid: 2,
  someKey5: 'someValue5'
}]

// expected result:

[{
  someKey1: 'someValue2',
  someKey4: 'someValue4'
}, {
  someKey2: 'someValue2',
  someKey5: 'someValue5',
  {
    id: 3,
    someKey3: 'someValue3'
  }
}]

Ответы [ 6 ]

3 голосов
/ 28 января 2020

Вы можете получить все идентификаторы и идентификаторы из обоих наборов массивов и поместить их в набор, а затем превратить этот набор обратно в массив, чтобы получить список уникальных идентификаторов / идентификаторов. Затем вы можете создавать карты для обоих массивов. Отображение идентификаторов / идентификаторов для хранения соответствующих им свойств объекта. Используя уникальный массив идентификаторов / идентификаторов, вы можете .map() каждый идентификатор соответствующего ему объекта, хранящегося в Map s следующим образом:

const data1 = [{ id: 1, someKey1: 'someValue2'}, { id: 2, someKey2: 'someValue2' }, { id: 3, someKey3: 'someValue3' }]
const data2 = [{ uid: 1, someKey4: 'someValue4'}, { uid: 2, someKey5: 'someValue5' }];
const getMap = (arr, id) => new Map(arr.map(({[id]:_id, ...r}) => [_id, {...r}]));

const ids = [...new Set(data1.map(({id}) => id).concat(data2.map(({uid}) => uid)))];

const data1Map = getMap(data1, 'id');
const data2Map = getMap(data2, 'uid');

const result = ids.map(id => ({...(data1Map.get(id) || {}), ...(data2Map.get(id) || {})}));
console.log(result);

Основная причина создания набора состоит в том, что объекты из data2 будут сохранены, если data1 не имеет идентификатора этого объекта, и наоборот.

0 голосов
/ 28 января 2020

Вот функция, которая будет делать то, что вы ищете:

const objectMerge = (sourceData, joinData) => 
  sourceData.map(item => {
    const { id, ...restOfItem } = item
    const foundJoins = joinData.filter(obj => obj.uid === id)
    if (foundJoins.length === 0) {
      return item
    }
    const dataFromJoins = foundJoins.reduce((result, join) => { 
      // Return everything in the object except the UID
      const { uid, ...restOfFields } = join
      return Object.assign({}, result, restOfFields)
    }, {})
    return Object.assign({}, restOfItem, dataFromJoins)
  })

Вы можете увидеть, как она работает здесь: https://repl.it/@RobBrander / Object-Merger

0 голосов
/ 28 января 2020

Вы можете использовать функцию map. Кроме того, вы можете использовать Map collection для доступа к элементам с O(1):

const createObj = (fooObj, keyToFilter) => {
  if (fooObj)
    return Object.fromEntries(Object.entries(fooObj).filter(([k, v])=> k != keyToFilter ));
  return null;
}    

const result = data1.map(s=> ({...createObj(s,'id'), ...createObj(maps.get(s.id),'uid')}));

Пример:

const data1 = [{
  id: 1,
  someKey1: 'someValue2'
}, {
  id: 2,
  someKey2: 'someValue2'
}, {
  id: 3,
  someKey3: 'someValue3'
}];

const data2 = [{
  uid: 1,
  someKey4: 'someValue4'
}, {
  uid: 2,
  someKey5: 'someValue5'
}]

let maps = new Map(data2.map(s=> [s.uid, s]));
const createObj = (fooObj, keyToFilter) => {
  if (fooObj)
    return Object.fromEntries(Object.entries(fooObj).filter(([k, v])=> k != keyToFilter ));
  return null;
}

const result = data1.map(s=> ({...createObj(s,'id'), ...createObj(maps.get(s.id),'uid')}));
console.log(result);
0 голосов
/ 28 января 2020

Вот еще один подход, который не оптимизирован по производительности и менее лаконичен, чем другие ответы, но разбивает шаги вниз, чтобы прояснить, что происходит.

const data1 = [{ id: 1, someKey1: 'someValue2'}, { id: 2, someKey2: 'someValue2' }, { id: 3, someKey3: 'someValue3' }]
const data2 = [{ uid: 1, someKey4: 'someValue4'}, { uid: 2, someKey5: 'someValue5' }]

function mergeProperties(set1, linkingProperty1, set2, linkingProperty2){

  const keys1 = set1.map( item => item[linkingProperty1] );
  const keys2 = set2.map( item => item[linkingProperty2] );
  const mergedKeys = keys1.concat(keys2);
  const filteredKeys = mergedKeys.filter( key => !!key || key === 0); //truthy or actually number 0
  const uniqueKeys = filteredKeys.filter((a, b) => filteredKeys.indexOf(a) === b);

  // now we have a complete list, with no duplicates, of all possible ids

  const mergedArray = uniqueKeys.reduce( (accumulator, key) => {
      const resultInSet1 = set1.find( item => item[linkingProperty1] === key );
      const resultInSet2 = set2.find( item => item[linkingProperty2] === key );
      let item = {};
      if(resultInSet1){
        delete resultInSet1[linkingProperty1];
        item = {...resultInSet1};
      }
      if(resultInSet2){
        delete resultInSet2[linkingProperty2];
        item = {...item, ...resultInSet2};
      }
      return [...accumulator, item];
  }, []);

  return mergedArray;
}

console.log( mergeProperties(data1,"id",data2,"uid") );
0 голосов
/ 28 января 2020

Попробуйте следующий код:

let data1 = [{
  id: 1,
  someKey1: 'someValue2'
}, {
  id: 2,
  someKey2: 'someValue2'
}, {
  id: 3,
  someKey3: 'someValue3'
}]
let data2 = [{
  uid: 1,
  someKey4: 'someValue4'
}, {
  uid: 2,
  someKey5: 'someValue5'
}]

let result = [];

data1.forEach((obj, i) => {
  const targetValues = data2.filter(x => x.uid === obj.id);
  result[i] = obj;

  if (targetValues && targetValues.length) {
    delete obj.id;
    targetValues.forEach(value => {
      delete value.uid;
      result[i] = {...result[i], ...value};
    })
    data2 = data2.filter(x => x.uid !== obj.id);
  }
});
result = result.concat(data2);
console.log(result);
0 голосов
/ 28 января 2020

Вы можете создать функцию, которая выполняет итерацию массива данных, и поместить ее объект в новый массив, индекс которого равен id или uid

const data1 = [{ id: 1, someKey1: 'someValue2'}, { id: 2, someKey2: 'someValue2' }, { id: 3, someKey3: 'someValue3' }]
const data2 = [{ uid: 1, someKey4: 'someValue4'}, { uid: 2, someKey5: 'someValue5' }]

let result = [];
result = mergeIntoResult(result, data1, "id");
result = mergeIntoResult(result, data2, "uid");

console.log(JSON.stringify(result));

function mergeIntoResult(resultArray, dataArray, idProperty) {
    return dataArray.reduce((acc,curr) => {
      const index = curr[idProperty];
      acc[index] = acc[index] || {}; //Take existing object or create default
      acc[index] = {...acc[index], ...curr}; //Insert object data
      delete acc[index][idProperty]; //Delete the "id" or "uid" field from the new object
      return acc;
    }, resultArray);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...