获取ES6中的数组差异?

时间:2016-12-06 15:23:51

标签: javascript arrays ecmascript-6

所以我有两个数组:

const allLanguages = [ 'ES', 'EN', 'DE' ]
const usedLanguages = [ { id: 1, lang: 'EN' } ]

生成新阵列的最快方法是什么,这两者之间的区别是什么?在旧式的JavaScript中,你必须在另一个for循环中进行for循环,我认为......

例如:

const availableLanguages = [ 'ES', 'DE' ]

4 个答案:

答案 0 :(得分:22)

您可以使用filter()find()返回已过滤的数组。



const allLanguages = [ 'ES', 'EN', 'DE' ]
const usedLanguages = [ { id: 1, lang: 'EN' } ]

var result = allLanguages.filter(e => !usedLanguages.find(a => e == a.lang));
console.log(result)




您还可以map()第二个数组,然后使用includes()过滤掉重复数据。



const allLanguages = [ 'ES', 'EN', 'DE' ]
const usedLanguages = [ { id: 1, lang: 'EN' } ].map(e => e.lang);

var result = allLanguages.filter(e => !usedLanguages.includes(e));
console.log(result)




答案 1 :(得分:8)

基于集合的方法

受到@Ori Drori的出色答案的启发,这是一个纯粹的基于集合的解决方案。

const all = new Set(allLanguages);
const used = new Set(usedLanguages.map(({lang}) => lang));

const availableLanguages = setDifference(all, used);

,其中

const setDifference = (a, b) => new Set([...a].filter(x => !b.has(x)));

availableLanguages将是一个集合,因此要将其作为数组使用,您需要在其上执行Array.from[...map]

如果想要全部功能,那么

const not = fn => x => !fn(x);
const isIn = set => x => set.has(x);

现在写

const setDifference = (a, b) => new Set([...a].filter(not(isIn(b))));

有些人可能认为更具语义或可读性。

然而,这些解决方案有些不尽如人意,可能不是最理想的。即使Set#hasO(1),与O(n)find的{​​{1}}相比,整体效果仍为some,因为我们必须迭代通过O(n)的所有元素。最好从a中删除b中的元素,如另一个答案所示。这将是

a

我们无法使用const setDifference = (a, b) => { const result = new Set(a); b.forEach(x => result.delete(x)); return result; } ,因为套装无法使用reduce,我们不希望必须将该套件转换为数组才能使用它。但是我们可以使用forEach,它可以在集合中使用。如果a更大且b更小,则此替代方案更为可取。

很可能JS的某些未来版本将内置此功能,您只需说出

即可
const availableLanguages = all.difference(used)

基于发电机的方法

最后,如果我们有兴趣探索更多ES6功能,我们可以将其编写为生成非重复值的生成器,如

function* difference(array, excludes) {
  for (let x of array) 
    if (!excludes.includes(x)) yield x;
}

现在我们可以写

console.log([...difference(allLanguages, usedLanguages)]);

如果有很长的语言列表,可能会推荐使用此解决方案,可能会逐个出现,并且您希望获得未使用的语言流。

使用字典

如果想要O(1)在不使用集合的情况下查找排除列表,那么经典的方法是预先计算字典:

const dict = Object.assign({}, 
    ...usedLanguages.map(({lang}) => ({[lang]: true})));

const availableLanguages = allLanguages.filter(lang => lang in dict);

如果这种计算字典的方式对你来说太神秘了,那么有些人会使用reduce

const dict = usedLanguages.reduce((obj, {lang}) => {
  obj[lang] = true;
  return obj;
}, {});

Nina喜欢使用逗号运算符编写

const dict = usedLanguages.reduce((obj, {lang}) => (obj[lang] = true, obj), {});

可以节省一些花括号。

或者,因为JS仍然有for个循环: - ):

const dict = {};
for (x of usedLanguages) {
  dict[x.lang] = true;
}

嘿,你是那个说你想用ES6的人。

答案 2 :(得分:6)

您可以使用以下代码:

availableLanguages = allLanguages.filter((lang1) => !usedLanguages.some((lang2) => lang2.lang === lang1))

some函数与find相比鲜为人知,更适合于您想要检查数组中是否满足条件的情况。

答案 3 :(得分:3)

使用usedLanguages迭代Array#reducenew Set(allLanguages)作为起始值。从used每次迭代设置中删除语言。将结果传播到数组中。复杂度为O(n + m),其中n是usedLanguages数组的长度,m是allLanguages的长度:



const allLanguages = [ 'ES', 'EN', 'DE' ];
const usedLanguages = [{ id: 1, lang: 'EN' }];

const result = [...usedLanguages.reduce((r, { lang }) => {
  r.delete(lang);
  return r;
}, new Set(allLanguages))];

console.log(result);