简体   繁体   English

JS(ES6):基于id和连接子数组合并数组

[英]JS (ES6): Merge arrays based on id and concatenating sub arrays

I have two arrays, which look like this: 我有两个数组,看起来像这样:

const persons = [
  {
    id: 1,
    name: 'Peter',
    job: 'Programmer'
  },
  {
    id: 2,
    name: 'Jeff',
    job: 'Architect'
  },
];

const salaries = [
  {
    id: 1,
    salary: 3000,
    departments: ['A', 'B'] 
  },
  {
    id: 1,
    salary: 4000,
    departments: ['A', 'C']
  },
  {
    id: 2,
    salary: 4000,
    departments: ['C', 'D']
  }
];

Now I need to somehow merge this arrays to one, so that every id only exists once. 现在我需要以某种方式将这个数组合并为一个,这样每个id只存在一次。 Same keys should be replaced, except it is an array, then I want them to add/concat. 应该替换相同的键,除了它是一个数组,然后我希望它们添加/连接。 So the desired result should look something like this: 所以期望的结果看起来像这样:

const result = [
  {
    id: 1,
    name: 'Peter',
    job: 'Programmer',
    salary: 4000,
    departments: ['A', 'B', 'C'] 
  },
  {
    id: 2,
    name: 'Jeff',
    job: 'Architect',
    salary: 4000,
    departments: ['C', 'D']
  }
];

I have already tried: 我已经尝试过了:

// double id's, arrays get replaced
Object.assign({}, persons, salaries)

// loadsh: double id's, arrays get concatenated
_.mergeWith(persons, salaries, (objValue, srcValue) => {
    if (_.isArray(objValue)) {
        return objValue.concat(srcValue);
    }
});

// gives me a map but replaces arrays
new Map(salaries.map(x => [x.id, x])

Does anyone have an idea how to accomplish this? 有谁知道如何做到这一点?

You could use a Map and iterate all properties and check the type for adding unique values to the arrays. 您可以使用Map并迭代所有属性并检查类型以向数组添加唯一值。

 var persons = [{ id: 1, name: 'Peter', job: 'Programmer' }, { id: 2, name: 'Jeff', job: 'Architect' }], salaries = [{ id: 1, salary: 3000, departments: ['A', 'B'] }, { id: 1, salary: 4000, departments: ['A', 'C'] }, { id: 2, salary: 4000, departments: ['C', 'D'] }], result = Array.from( salaries .reduce( (m, o) => { var t = m.get(o.id) || {}; Object.keys(o).forEach(k => { if (Array.isArray(o[k])) { t[k] = t[k] || []; o[k].forEach(v => t[k].includes(v) || t[k].push(v)); } else if (t[k] !== o[k]) { t[k] = o[k]; } }); return m; }, persons.reduce((m, o) => m.set(o.id, Object.assign({}, o)), new Map) ) .values() ); console.log(result); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

You can concat the arrays, than combine all items with the same id using Array.reduce() , and a Map . 您可以连接数组,而不是使用Array.reduce()Map组合具有相同id所有项。

to combine objects with the same id , get the object from the Map. 要组合具有相同id的对象,请从Map获取对象。 Iterate the new Object.entries() with Array.forEach() . 使用Array.forEach()迭代新的Object.entries() Array.forEach() Check if existing value is an array, if not assign the value. 检查现有值是否为数组,如果不是则赋值。 If it is an array, combine the arrays, and make the items unique using a Set with array spread . 如果是数组,请组合数组,并使用带数组传播Set使项目唯一。

To convert the Map back to an array, you can spread the Map.values() iterator. 要将Map转换回数组,可以传播Map.values()迭代器。

 const persons = [{"id":1,"name":"Peter","job":"Programmer"},{"id":2,"name":"Jeff","job":"Architect"}]; const salaries = [{"id":1,"salary":3000,"departments":["A","B"]},{"id":1,"salary":4000,"departments":["A","C"]},{"id":2,"salary":4000,"departments":["C","D"]}]; const result = [...persons.concat(salaries) .reduce((r, o) => { r.has(o.id) || r.set(o.id, {}); const item = r.get(o.id); Object.entries(o).forEach(([k, v]) => item[k] = Array.isArray(item[k]) ? [...new Set([...item[k], ...v])] : v ); return r; }, new Map()).values()]; console.log(result); 

You can use map() , filter() , reduce() , Object.assign() and Spread syntax to achieve required result. 您可以使用map()filter()reduce()Object.assign()Spread syntax来实现所需的结果。

DEMO DEMO

 const persons = [{ id: 1, name: 'Peter', job: 'Programmer' }, { id: 2, name: 'Jeff', job: 'Architect' }], salaries = [{ id: 1, salary: 3000, departments: ['A', 'B'] }, { id: 1, salary: 4000, departments: ['A', 'C'] }, { id: 2, salary: 4000, departments: ['C', 'D'] }]; let output = persons.map(obj => { let filter = salaries.filter(v => v.id == obj.id); if (filter) { let departments = filter.reduce((r, v) => [...v.departments, ...r], []); Object.assign(obj, { salary: filter[filter.length - 1].salary, departments: departments.filter((item, pos) => departments.indexOf(item) == pos).sort() }); } return obj; }); console.log(output) 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM