如何通过模式对数组进行排序,以使模式中不存在的元素不会移动到数组的末尾,但保留其顺序?
有一个例子:
let input = ['Apple', 'Banana', 'Cherry', 'Grape', 'Mango', 'Orange', 'Peach']
let pattern = ['Orange', 'Peach', 'Banana', 'Grape']
// desired output
let output = ['Apple', 'Orange', 'Peach', 'Banana', 'Cherry', 'Grape', 'Mango']
图案的长度可以等于,小于或大于输入数组的长度。
标准排序:
input.sort( (a, b) => {
let indexA = pattern.indexOf(a);
let indexB = pattern.indexOf(b);
return Math.sign(indexA - indexB);
});
// result:
// Apple,Cherry,Mango,Orange,Peach,Banana,Grape
// elements that are not present in pattern have been moved to the left
但是,我们要保留模式阵列中不存在的元素的相对位置。最有效的方法是什么?
使用示例:对表列重新排序(有些列可能被隐藏,但我们记住它们的顺序)。
答案 0 :(得分:1)
您可以为索引获取一个对象,并在一个数组中获取所需模式的所有索引,对其进行排序并映射原始数组,然后获取该模式的项目(已排序的项目)。
var input = ['Apple', 'Banana', 'Cherry', 'Grape', 'Mango', 'Orange', 'Peach'],
pattern = ['Orange', 'Peach', 'Banana', 'Grape'],
patternO = Object.assign(...pattern.map((k, v) => ({ [k]: v }))),
indices = [...input.keys()]
.filter(i => input[i] in patternO)
.sort((a, b) => patternO[input[a]] - patternO[input[b]]),
result = input.map((j => (v, i) => v in patternO ? input[indices[j++]]: v)(0));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 1 :(得分:1)
patternElementIndexTable
只是为了加快某些操作的速度,可以将其删除,然后将indexOf
放在相关位置。这将降低算法的顺序并在输入为例如大于几千个项目。
首先,仅考虑input
中出现的pattern
的元素,并创建该列表和input
之间的索引的映射:
input.map((_, i) => i).filter(i => input[i] in patternElementIndexTable)
然后,我根据映射将分配映射到intermediary
的任何整数索引,以更改input
的相关属性。这基本上意味着在intermediary
上进行操作就像在input
上进行操作,而只是考虑了所需的元素。
因此,对中介物进行排序即可达到预期的效果:
let input = ['Apple', 'Banana', 'Cherry', 'Grape', 'Mango', 'Orange', 'Peach'];
let pattern = ['Orange', 'Peach', 'Banana', 'Grape'];
let patternElementIndexTable = pattern.reduce((p, c, i) => (p[c] = i, p), {});
let intermediary = new Proxy(
Object.seal(input.map((_, i) => i).filter(i => input[i] in patternElementIndexTable)),
{
get: (target, prop) => {
if (Number.isInteger(+prop) && +prop >= 0) {
if (+prop >= target.length)
return undefined;
return input[target[prop]];
}
return target[prop];
},
set: (target, prop, value) => {
if (Number.isInteger(+prop) && +prop >= 0) {
if (+prop >= target.length) {
return false;
}
input[target[prop]] = value;
return true;
}
return false;
}
}
);
intermediary.sort((a, b) => patternElementIndexTable[a] - patternElementIndexTable[b]);
console.log(input);
我首先想到的是重新实现某种添加了该功能的排序算法,但是这种方法似乎更加通用(对于其他不会改变长度的变异操作也应如此,例如reverse
,{{1 }}或自定义函数)。
请注意,仅更改fill
的人不应该使用intermediary
。添加或删除元素是无效的操作。非整数索引属性的任何更改都是无效操作。
答案 2 :(得分:0)
您可以循环input
数组,并在pattern
数组中每次出现的元素出现时增加一个计数器变量,并使用具有该索引的元素。
let input = ['Apple', 'Banana', 'Cherry', 'Grape', 'Mango', 'Orange', 'Peach']
let pattern = ['Orange', 'Peach', 'Banana', 'Grape'];
let current = 0;
input.forEach((e, i) => {
if (pattern.includes(e)) input[i] = pattern[current++]
})
console.log(input)