我有一个数组列表,其中相同的项目可能出现在不同的列表中(但不在同一个列表中)。
我正在尝试对数组进行排序,以便匹配项在所有数组中具有相同的索引。
我也在尝试尽可能填补空白,但如果某些位置仍未定义,那也没关系。
条件
输入
const myWrapper [
{ foo: [] },
{ foo: ['A', 'B', 'C', 'D'] },
{ foo: ['X', 'A', 'E', 'C'] },
{ foo: ['X', 'F', 'C', 'G', 'H'] },
{ foo: ['C'] }
];
所需输出 const myWrapper [
{ foo: [] },
{ foo: ['B', 'A', 'C', 'D'] },
{ foo: ['X', 'A', 'C', 'E'] },
{ foo: ['X', 'F', 'C', 'G', 'H'] },
{ foo: [undefined, undefined, 'C'] }
];
有没有一种巧妙的方法来实现这一目标?我的尝试,从右侧排序并使用 tmp 变量来交换项目。
这似乎效果不佳,因为以下位置有时会移动先前的项目,从而弄乱先前迭代中设置的顺序。
let tmp;
myWrapper.forEach((item, wrapperIndex) => {
item.foo.forEach((currentFoo, fooIndex) => {
// Search for match in the previous foo
if(myWrapper[wrapperIndex - 1]) {
const prevFoo = myWrapper[wrapperIndex - 1].foo;
const prevIndex = prevFoo.indexOf(item);
if (prevIndex >= 0 && prevIndex !== fooIndex) {
tmp = prevFoo[fooIndex];
prevFoo[fooIndex] = prevEvents[prevIndex];
prevFoo[prevIndex] = tmp;
}
}
});
});
编辑:问题还在于循环对单个项目(实际上是对象,我使用字符串来简化)执行其他操作,所以我不能从右侧移动(当前项目)。The output is rendered via Angular using 2 nested *ngFor so the final result has to maintain this array structure.
最佳答案
编辑
一个更简单的解决方案,使用与我原始答案相同的重复映射,然后使用简单的交换算法将重复值移动到相应的索引中。
const myWrapper = [
{ foo: [] },
{ foo: ['A', 'B', 'C', 'D'] },
{ foo: ['X', 'A', 'E', 'C'] },
{ foo: ['X', 'F', 'C', 'G', 'H'] },
{ foo: ['C'] }
];
// find dupes and create map of indexes
let
seen = new Set,
dupeMap = {}, d = 0;
for (const { foo } of myWrapper) {
for (const x of foo) {
seen.has(x)
? dupeMap[x] ??= d++
: seen.add(x);
}
}
// swap duplicates into appropriate indexes
for (const { foo } of myWrapper) {
let
i, j, temp;
for (i = 0; i < foo.length; i++) {
j = dupeMap[foo[i]];
if (j !== undefined && j !== i) {
temp = foo[i];
foo[i] = foo[j];
foo[j] = temp;
i--;
}
}
}
myWrapper.forEach(({ foo }) => console.log(`{foo: [${foo.map(e => e ?? ' ').join(', ')}]}`));
.as-console-wrapper { max-height: 100% !important; top: 0; }
原答案
这是一个避免排序的相当简单的解决方案。它首先创建一个对象,其中包含重复值的 Prop 和最终数组中该值的预期索引作为值。
然后它遍历每个
foo
数组通过重复映射中的索引将重复值放置在临时数组中,并将唯一值推送到第二个临时数组。在退出之前,它会尝试从唯一数组中的任何值回填临时重复数组中的漏洞。
这会改变
myWrapper
阵列到位。const myWrapper = [
{ foo: [] },
{ foo: ['A', 'B', 'C', 'D'] },
{ foo: ['X', 'A', 'E', 'C'] },
{ foo: ['X', 'F', 'C', 'G', 'H'] },
{ foo: ['C'] }
];
// find dupes and create map of indexes
let
seen = new Set,
dupeMap = {}, d = 0;
for (const { foo } of myWrapper) {
for (const x of foo) {
seen.has(x)
? dupeMap[x] ??= d++
: seen.add(x);
}
}
for (const obj of myWrapper) {
// collect elements into dupe/unique temp arrays
const
{ foo } = obj,
dTemp = [], uTemp = [];
for (const e of foo) {
(e in dupeMap)
? dTemp[dupeMap[e]] = e
: uTemp.push(e);
}
// backfill empty indexes in dupe temp array
for (const [i, d] of dTemp.entries()) {
if (d === undefined && uTemp.length) {
dTemp.splice(i, 1, uTemp.shift());
}
}
// concat back into foo
obj.foo = [...dTemp, ...uTemp];
}
myWrapper.forEach(({ foo }) => console.log(`{foo: [${foo.map(e => e ?? ' ').join(', ')}]}`));
.as-console-wrapper { max-height: 100% !important; top: 0; }
关于Javascript:对齐并行数组索引避免重叠,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67583456/