按模式对数组进行排序,保留在模式中找不到的元素的顺序



如何按模式对数组进行排序,使模式中不存在的元素不会移动到数组的末尾,而是保留它们的顺序?

有一个例子:

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

然而,我们希望保留模式数组中不存在的元素的相对位置。实现这一目标的最有效方法是什么?

使用示例:重新排序表列(有些列可能是隐藏的,但我们记住它们的顺序(。

patternElementIndexTable只是为了加快一些操作,它可以被移除,indexOf在相关位置被拿走。当输入例如大于几千个项目时,这将降低算法的顺序并产生问题。

首先,只考虑出现在pattern中的input元素,并在该列表和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);

我最初考虑在添加该功能的情况下重新实现一些排序算法,但这种方法似乎更通用(这应该适用于任何其他不会改变长度的变异操作,例如reversefill或自定义函数(。

请注意,在自行更改input之后,不应使用intermediary。添加或删除元素是无效操作。对非整数索引属性的任何更改都是无效操作。

您可以将一个对象作为索引,并在数组中获取所需模式的所有索引,对其进行排序并映射原始数组,然后获取模式中的项,即排序后的项。

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; }

您只需循环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)

最新更新