如果您能够使用 ES6 功能,则可以使用生成器来避免创建大型中间数组。您似乎想要一组排序集,其中行仅包含唯一值。正如其他人也提到的那样,您可以通过从与您的键匹配的对象的笛卡尔积开始来解决此问题:input
'use strict';
function* product(...seqs) {
const indices = seqs.map(() => 0),
lengths = seqs.map(seq => seq.length);
// A product of 0 is empty
if (lengths.indexOf(0) != -1) {
return;
}
while (true) {
yield indices.map((i, iseq) => seqs[iseq][i]);
// Update indices right-to-left
let i;
for (i = indices.length - 1; i >= 0; i--) {
indices[i]++;
if (indices[i] == lengths[i]) {
// roll-over
indices[i] = 0;
} else {
break;
}
}
// If i is negative, then all indices have rolled-over
if (i < 0) {
break;
}
}
}
生成器仅在迭代之间保存索引并按需生成新行。要实际加入与您的键匹配的对象input
,您首先必须创建一个查找:
function join(keys, values) {
const lookup = [...new Set(keys)].reduce((o, k) => {
o[k] = [];
return o;
}, {});
// Iterate over array indices instead of objects them selves.
// This makes producing unique rows later on a *lot* easier.
for (let i of values.keys()) {
const k = Object.keys(values[i])[0];
if (lookup.hasOwnProperty(k)) {
lookup[k].push(i);
}
}
return product(...keys.map(k => lookup[k]));
}
然后,您需要过滤掉包含重复值的行:
function isUniq(it, seen) {
const notHadIt = !seen.has(it);
if (notHadIt) {
seen.add(it);
}
return notHadIt;
}
function* removeDups(iterable) {
const seen = new Set();
skip: for (let it of iterable) {
seen.clear();
for (let x of it) {
if (!isUniq(x, seen)) {
continue skip;
}
}
yield it;
}
}
还有全局唯一的行(set-of-sets 方面):
function* distinct(iterable) {
const seen = new Set();
for (let it of iterable) {
// Bit of a hack here, produce a known order for each row so
// that we can produce a "set of sets" as output. Rows are
// arrays of integers.
const k = it.sort().join();
if (isUniq(k, seen)) {
yield it;
}
}
}
把它绑起来:
function* query(input, arr) {
for (let it of distinct(removeDups(join(input, arr)))) {
// Objects from rows of indices
yield it.map(i => arr[i]);
}
}
function getResults(input, arr) {
return Array.from(query(input, arr));
}
在行动:
const arr = [
{"a": "x"},
{"b": "0"},
{"c": "k"},
{"a": "nm"},
{"b": "765"},
{"ab": "i"},
{"bc": "x"},
{"ab": "4"},
{"abc": "L"}
];
console.log(getResults(["a", "a", "ab"], arr));
/*
[ [ { a: 'x' }, { a: 'nm' }, { ab: 'i' } ],
[ { a: 'x' }, { a: 'nm' }, { ab: '4' } ] ]
*/
和强制性的jsFiddle。