[英]Merge an array by comparing the array of objects inside the array
我有以下数组
var array = [
{
group: "FL",
list: [
{ key: "A", value: "Alaska" },
{ key: "B", value: "Brazil" },
{ key: "C", value: "California" }
]
},
{
group: "NZ",
list: [
{ key: "A", value: "Alaska" },
{ key: "B", value: "Brazil" },
{ key: "D", value: "Delhi" }
]
},
{
group: "QA",
list: [
{ key: "A", value: "Alaska" },
{ key: "B", value: "Brazil" },
{ key: "C", value: "California" }
]
}
]
我需要检查列表数组,如果列表数组中的所有对象都完全相同,那么我需要将其合并如下:
[
{
group: "FL,QA",
list: [
{ key: "A", value: "Alaska" },
{ key: "B", value: "Brazil" },
{ key: "C", value: "California" }
]
},
{
group: "NZ",
list: [
{ key: "A", value: "Alaska" },
{ key: "B", value: "Brazil" },
{ key: "D", value: "Delhi" }
]
}
]
我通过使用reduce方法循环数组和其他两个函数来比较对象来尝试这个,但不知何故它不起作用
array.reduce(async(acc, item) => {
const exist = await compareObjects(acc, item);
if (exist) {
acc[exist.index].group= exist.group + ',' + item.group;
} else {
acc.push(item)
}
return acc;
}, [])
async function compareObjects(o1, o2) {
for (let i = 0; i < o1.length; i++) {
const value = await checkObjs(o1[i].list, o2.list);
if(value) { return {index:i , group: o1[i].group} }
}
}
function checkObjs(arr1, arr2) {
return arr1.length === arr2.length && arr1.every((el, i) => objectsEqual(el, arr2[i]))
}
const objectsEqual = (o1, o2) =>
Object.keys(o1).length === Object.keys(o2).length
&& Object.keys(o1).every(p => o1[p] === o2[p]);
任何帮助,将不胜感激 。 谢谢
您可以使用Array.reduce()
创建输入对象的映射。
我们将创建一个函数getListKey()
来根据每个对象列表创建一个唯一的键。
一旦我们有了地图,我们就可以使用Object.values()
来获取数组结果:
var array = [ { group: "FL", list: [ { key: "A", value: "Alaska" }, { key: "B", value: "Brazil" }, { key: "C", value: "California" } ] }, { group: "NZ", list: [ { key: "A", value: "Alaska" }, { key: "B", value: "Brazil" }, { key: "D", value: "Delhi" } ] }, { group: "QA", list: [ { key: "A", value: "Alaska" }, { key: "B", value: "Brazil" }, { key: "C", value: "California" } ] } ] function getListKey(list) { return JSON.stringify(list.sort(({ key: a }, { key: b }) => a.localeCompare(b))); } const result = Object.values(array.reduce((acc, { group, list }) => { const key = getListKey(list); if (!acc[key]) { acc[key] = { group, list }; } else { acc[key].group += "," + group; } return acc; }, {})) console.log('Result:', result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
另一种方法是再次使用Array.reduce()
,但使用 lodash _.isEqual()函数进行列表比较。 这进行了深入的比较。 我们将它与Array.find()
一起使用来获取任何重复的列表。
var array = [ { group: "FL", list: [ { key: "A", value: "Alaska" }, { key: "B", value: "Brazil" }, { key: "C", value: "California" } ] }, { group: "NZ", list: [ { key: "A", value: "Alaska" }, { key: "B", value: "Brazil" }, { key: "D", value: "Delhi" } ] }, { group: "QA", list: [ { key: "A", value: "Alaska" }, { key: "B", value: "Brazil" }, { key: "C", value: "California" } ] } ] const result = array.reduce((acc, cur) => { const foundItem = acc.find(item => _.isEqual(item.list, cur.list)); if (foundItem) { foundItem.group += `,${cur.group}`; } else { acc.push(cur); } return acc; }, []) console.log('Result:', result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" referrerpolicy="no-referrer"></script>
你对async
使用让你在这里绊倒,我不确定你使用它的原因。
为了使您的代码按原样工作,您需要在每次迭代时await
累加器,并将reduce()
的结果分配给某些东西。
var array = [ { group: 'FL', list: [ { key: 'A', value: 'Alaska' }, { key: 'B', value: 'Brazil' }, { key: 'C', value: 'California' }, ], }, { group: 'NZ', list: [ { key: 'A', value: 'Alaska' }, { key: 'B', value: 'Brazil' }, { key: 'D', value: 'Delhi' }, ], }, { group: 'QA', list: [ { key: 'A', value: 'Alaska' }, { key: 'B', value: 'Brazil' }, { key: 'C', value: 'California' }, ], }, ]; function checkObjs(arr1, arr2) { const objectsEqual = (o1, o2) => Object.keys(o1).length === Object.keys(o2).length && Object.keys(o1).every((p) => o1[p] === o2[p]); return arr1.length === arr2.length && arr1.every((el, i) => objectsEqual(el, arr2[i])); } async function compareObjects(o1, o2) { for (let i = 0; i < o1.length; i++) { const value = await checkObjs(o1[i].list, o2.list); if (value) { return { index: i, group: o1[i].group }; } } } // assign the result of reduce to a variable const result = array.reduce(async (acc, item) => { acc = await acc; // await the returned accumulator Promise const exist = await compareObjects(acc, item); if (exist) { acc[exist.index].group = exist.group + ',' + item.group; } else { acc.push(item); } return acc; }, []); result.then((r) => console.log(r));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Reduce 不适用于async/await
。 如果您没有async
代码 - 从 API 获取某些内容或使用来自 Promise 的数据,您应该删除async/await
,因为它是同步的。
如果您的代码使用了一些异步 API - 尝试使用类似的东西:
export const reduceAsync = async (array, transformer, initialvalue) => {
let accumolator = typeof initialValue !== 'undefined' ? initialValue : array[0];
for (let i = 0; i < array.length; i++) {
accumolator = await transformer(accumolator, array[i], i, array);
}
return accumolator;
};
上面的函数是可重用的,并遵循此处定义的规范: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
我认为我建议解决这个问题的方法是将其分解并(希望)使用库函数来解决一些更复杂的问题。 例如用lodash
你可以说
import isEqual from "lodash/isEqual";
const arr = [
{
group: "FL",
list: [
{ key: "A", value: "Alaska" },
{ key: "B", value: "Brazil" },
{ key: "C", value: "California" }
]
},
{
group: "NZ",
list: [
{ key: "A", value: "Alaska" },
{ key: "B", value: "Brazil" },
{ key: "D", value: "Delhi" }
]
},
{
group: "QA",
list: [
{ key: "A", value: "Alaska" },
{ key: "B", value: "Brazil" },
{ key: "C", value: "California" }
]
}
];
function groupBy<T, R>(
a: T[],
iteritem: (t: T) => R,
compare: (a: R, b: R) => boolean = isEqual
) {
const groups: T[][] = [];
const rs = a.map(iteritem);
for (let i = 0; i < rs.length; i++) {
let added = false;
const r = rs[i];
for (let j = 0; j < groups.length; j++) {
if (compare(r, iteritem(groups[j][0]))) {
groups[j].push(a[i]);
added = true;
break;
}
}
if (!added) {
groups.push([a[i]]);
}
}
return groups;
}
const grouped = groupBy(arr, (a) => a.list);
const combined = [];
for (const g of grouped) {
combined.push({
group: g.map(({ group }) => group).join(","),
list: g[0].list
});
}
console.log(JSON.stringify(combined, undefined, 2));
这不是一次性的答案,因为groupBy
可以重复使用。 我最初想使用groupBy
的lodash
但它不接受自定义相等函数。
这是一种可能的解决方案:
const sorted = [];
for (let i = 0; i < groups.length; i++) {
const identicalLists = [];
for (let j = i; j < groups.length; j++) {
const isIdentical =
JSON.stringify(groups[i].list) === JSON.stringify(groups[j].list);
const found = !!sorted.flat().find((item) => item === groups[j].group);
if (isIdentical && !found) {
identicalLists.push(groups[j].group);
}
}
if (identicalLists.length > 0) {
sorted.push(identicalLists);
}
}
const answer = sorted.map((item) => {
const first = groups.find((group) => group.group === item[0]);
return { group: item, list: first.list };
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.