typescript 合并2个对象数组,并为不存在的属性添加空值

guicsvcw  于 2023-05-23  发布在  TypeScript
关注(0)|答案(7)|浏览(251)

我有一个marks数组,包含具有idmarks属性的对象。我还有一个user数组,包含具有idnamegraderesult属性的对象。

var marks = [
  { id: '1', marks: 70 },
  { id: '2', marks: 40 },
  { id: '3', marks: 95 },
  { id: '4', marks: 50 },
];

var user = [
  { id: '1', name: 'sam', grade: 1, result: 'Pass' },
  { id: '2', name: 'peter', grade: 2, result: 'Pass' },
  { id: '5', name: 'John', grade: 1, result: 'Fail' },
  { id: '6', name: 'anna', grade: 3, result: 'Fail' },
];

我想合并2个数组对象并生成如下结果。如果找到了与id匹配的,我们需要合并这些对象,否则为两个数组中不存在的属性置null

var result = [
  { id: '1', marks: 70, name: 'sam', grade: 1, result: 'Pass' },
  { id: '2', marks: 40, name: 'peter', grade: 2, result: 'Pass' },
  { id: '3', marks: 95, name: null, grade: null, result: null },
  { id: '4', marks: 50, name: null, grade: null, result: null },
  { id: '5', marks: null, name: 'John', grade: 1, result: 'Fail' },
  { id: '6', marks: null, name: 'anna', grade: 3, result: 'Fail' },
];

我已经尝试了下面的代码段,但它没有生成期望的结果。它只根据第一个数组生成值

marks.forEach((item) => map.set(item.id, item));
user.forEach((item) => map.set(item.id, { ...map.get(item.id), ...item }));
const mergedArr = Array.from(map.values());

我该怎么解决这个问题?

jm81lzqq

jm81lzqq1#

方法:

  • 我们首先需要属性列表,这两个项目列表中都有。
  • 构造一个示例空项,如果有空项的值,则覆盖空项。

如果你知道所需的属性,你可以跳过构建attributes集合,直接在那里硬编码它们。下面的脚本动态生成当前属性的列表。

// Sample data
const marks = [
  { id: '1', marks: 70 },
  { id: '2', marks: 40 },
  { id: '3', marks: 95 },
  { id: '4', marks: 50 },
];

const users = [
  { id: '1', name: 'sam', grade: 1, result: 'Pass' },
  { id: '2', name: 'peter', grade: 2, result: 'Pass' },
  { id: '5', name: 'John', grade: 1, result: 'Fail' },
  { id: '6', name: 'anna', grade: 3, result: 'Fail' },
];

// Construct a set of required attributes 
const attributes = new Set();
marks.forEach(mark => Object.keys(mark).forEach(e => attributes.add(e)));
users.forEach(user => Object.keys(user).forEach(e => attributes.add(e)));

// Construct an empty sample object
const sample = {}
attributes.forEach((attribute) => {
    sample[attribute] = null;
})

// Merge all the items with sample object
const mergedItems = {}
marks.forEach(mark => {
    if (mergedItems[mark.id]) {
        mergedItems[mark.id] = {
            ...mergedItems[mark.id],
            ...mark
        };
    } else {
        mergedItems[mark.id] = {
            ...sample,
            ...mark
        };
    }
});
users.forEach(user => {
    if (mergedItems[user.id]) {
        mergedItems[user.id] = {
            ...mergedItems[user.id],
            ...user
        };
    } else {
        mergedItems[user.id] = {
            ...sample,
            ...user
        };
    }
});

// Take out values alone. Don't need keys.
const result = Object.values(mergedItems);

// Print them to console
document.write(JSON.stringify(result, null, 2))
xv8emn3q

xv8emn3q2#

我为你提供了一个参考,看起来很丑,但工作(它将支持动态属性

var marks = [
  { id: '1', marks: 70 },
  { id: '2', marks: 40 },
  { id: '3', marks: 95 },
  { id: '4', marks: 50 },
];

var user = [
  { id: '1', name: 'sam', grade: 1, result: 'Pass' },
  { id: '2', name: 'peter', grade: 2, result: 'Pass' },
  { id: '5', name: 'John', grade: 1, result: 'Fail' },
  { id: '6', name: 'anna', grade: 3, result: 'Fail' },
];

let keys1 = Object.keys(marks[0]).filter(k => k !== 'id')
let keys2 = Object.keys(user[0]).filter(k => k !== 'id')

let ids = new Set([...marks.map(m => m.id), ...user.map(u => u.id)])
let result = []
for (id of ids) {
   let obj1 = marks.find(i => i.id == id) ?? {}
   let obj2 = user.find(i => i.id == id) ?? {}
   obj = {
      id: id
   }
   for (k1 of keys1) {
      obj[k1] = obj1[k1] ?? null
   }
   for (k2 of keys2) {
      obj[k2] = obj2[k2] ?? null
   }

   result.push(obj)
}

console.log(result)
xe55xuns

xe55xuns3#

var marks = [
  { id: '1', marks: 70 },
  { id: '2', marks: 40 },
  { id: '3', marks: 95 },
  { id: '4', marks: 50 },
];

var users = [
  { id: '1', name: 'sam', grade: 1, result: 'Pass' },
  { id: '2', name: 'peter', grade: 2, result: 'Pass' },
  { id: '5', name: 'John', grade: 1, result: 'Fail' },
  { id: '6', name: 'anna', grade: 3, result: 'Fail' },
];

type Result = {
    id: string;
    name: string | null;
    grade: number | null;
    result: string | null;
    marks: number | null;
}

const userDefaults = {name: null, grade: null, result: null};
const userMarksDefaults = { marks: null }

// convert the marks array into a map (object) for faster access
const marksAsMap = marks.reduce((accumulator, userMarks) => {
  accumulator[userMarks.id] = userMarks;
  return accumulator;
}, {} as Record<string, typeof marks[number]>);

// convert the users array into a map (object) for faster access
const usersAsMap = users.reduce((accumulator, user) => {
  accumulator[user.id] = user;
  return accumulator;
}, {} as Record<string, typeof users[number]>);

// Grab all ids from both arrays
const uniqueIds = Array.from(new Set([...Object.keys(marksAsMap), ...Object.keys(usersAsMap)]));

const result = uniqueIds.reduce((accumulator, uniqueId) => {
  // default all properties to null and override with actual values
  const user = { ...userDefaults, ...usersAsMap[uniqueId] }
  const userMarks = { ...userMarksDefaults, ...marksAsMap[uniqueId] };
  accumulator.push({
    ...user,
    ...userMarks,
    id: uniqueId,
  });
  return accumulator;
}, [] as Result[])

console.log(result)
imzjd6km

imzjd6km4#

下面是如何在Typescript中实现这一点:

const marks = [
    { id: '1', marks: 70 },
    { id: '2', marks: 40 },
    { id: '3', marks: 95 },
    { id: '4', marks: 50 },
  ];
  
  const user = [
    { id: '1', name: 'sam', grade: 1, result: 'Pass' },
    { id: '2', name: 'peter', grade: 2, result: 'Pass' },
    { id: '5', name: 'John', grade: 1, result: 'Fail' },
    { id: '6', name: 'anna', grade: 3, result: 'Fail' },
  ];
  
  type MergedObj = {
    id: string;
    marks: number | null;
    name: string | null;
    grade: number | null;
    result: string | null;
  };
  
  const mergedArr: MergedObj[] = marks.map((mark) => {
    const userObj = user.find((u) => u.id === mark.id);
    return { ...mark, ...(userObj || { name: null, grade: null, result: null }) };
  });
  
  user.forEach((u) => {
    const existingMark = mergedArr.find((mark) => mark.id === u.id);
    if (!existingMark) {
      mergedArr.push({ ...u, marks: null });
    }
  });
  
  console.log(mergedArr);

输出将是:

[
  { id: '1', marks: 70, name: 'sam', grade: 1, result: 'Pass' },
  { id: '2', marks: 40, name: 'peter', grade: 2, result: 'Pass' },
  { id: '3', marks: 95, name: null, grade: null, result: null },
  { id: '4', marks: 50, name: null, grade: null, result: null },
  { id: '5', marks: null, name: 'John', grade: 1, result: 'Fail' },
  { id: '6', marks: null, name: 'anna', grade: 3, result: 'Fail' }
]
qrjkbowd

qrjkbowd5#

一个建议是使用**map()**来遍历marks数组中的每个对象,并应用逻辑来合并和填充缺少的属性。
在这里,map()迭代对象并应用逻辑。逻辑由find()处理:它遍历每个元素并检查ID是否与marks中的对象ID匹配。
concat()组合两个或多个数组以创建一个新数组。

  • 代码过滤器以查找不匹配的对象,当marks* 中没有匹配时,第二个map用于将它们标记为null。
var marks = [
  { id: '1', marks: 70 },
  { id: '2', marks: 40 },
  { id: '3', marks: 95 },
  { id: '4', marks: 50 },
];

var user = [
  { id: '1', name: 'sam', grade: 1, result: 'Pass' },
  { id: '2', name: 'peter', grade: 2, result: 'Pass' },
  { id: '5', name: 'John', grade: 1, result: 'Fail' },
  { id: '6', name: 'anna', grade: 3, result: 'Fail' },
];

var mergedArr = marks.map(mark => {
  const userObj = user.find(userItem => userItem.id === mark.id) || {};
  return {
    id: mark.id,
    marks: mark.marks ?? null,
    name: userObj.name ?? null,
    grade: userObj.grade ?? null,
    result: userObj.result ?? null,
    ...mark,
  };
}).concat(user.filter(userItem => !marks.find(markItem => markItem.id === userItem.id)).map(userItem => ({
  id: userItem.id,
  marks: null,
  name: userItem.name ?? null,
  grade: userItem.grade ?? null,
  result: userItem.result ?? null,
})));

console.log(mergedArr);
bnl4lu3b

bnl4lu3b6#

通过使用Set,我们可以确定属于两个数组的id的唯一集合和keys的唯一集合。

const ids = [...new Set([...marks.map(m => m.id), ...user.map(u => u.id)])];
// ids = Array ["1", "2", "3", "4", "5", "6"]

const keys = [...new Set([...Object.keys(marks[0]),...Object.keys(user[0])])];
// keys = Array ["id", "marks", "name", "grade", "result"]

我们构造一个blank对象,它拥有所有键,但值为null。

const blank = keys.reduce((p,c) => { p[c] = null; return p; }, { });
// blank = Object { id: null, marks: null, name: null, grade: null, result: null }

然后我们使用JavaScript spread operator(...)将blank对象与相应的marks对象和/或user对象合并。

id => ({...blank,
         ...marks.find(m => m.id == id),
         ...user.find(u => u.id == id)})

下面是完整的代码:

const marks = [
    { id: '1', marks: 70 },
    { id: '2', marks: 40 },
    { id: '3', marks: 95 },
    { id: '4', marks: 50 },
];
const user = [
    { id: '1', name: 'sam', grade: 1, result: 'Pass' },
    { id: '2', name: 'peter', grade: 2, result: 'Pass' },
    { id: '5', name: 'John', grade: 1, result: 'Fail' },
    { id: '6', name: 'anna', grade: 3, result: 'Fail' },
];
const ids = [...new Set([...marks.map(m => m.id), ...user.map(u => u.id)])];
const keys = [...new Set([...Object.keys(marks[0]),...Object.keys(user[0])])];
const blank = keys.reduce((p,c) => { p[c] = null; return p; }, { });
const result = ids.map(id => ({...blank,
                               ...marks.find(m => m.id == id),
                               ...user.find(u => u.id == id)}));
for (let r of result) console.log(JSON.stringify(r));

// Outputs:
// {"id":"1","marks":70,"name":"sam","grade":1,"result":"Pass"}
// {"id":"2","marks":40,"name":"peter","grade":2,"result":"Pass"}
// {"id":"3","marks":95,"name":null,"grade":null,"result":null}
// {"id":"4","marks":50,"name":null,"grade":null,"result":null}
// {"id":"5","marks":null,"name":"John","grade":1,"result":"Fail"}
// {"id":"6","marks":null,"name":"anna","grade":3,"result":"Fail"}
lf3rwulv

lf3rwulv7#

试试这个对你有帮助

let data =user.map((user,i)=>{
    let userMarks = marks.find(m=>m.id === user.id);
    return {
        ...user,
        ...userMarks
    }
    
})
console.log("DATA=",data)

相关问题