Javascript 获取ES6中数组的差异?

Javascript 获取ES6中数组的差异?,javascript,arrays,ecmascript-6,Javascript,Arrays,Ecmascript 6,所以我有两个数组: const allLanguages = [ 'ES', 'EN', 'DE' ] const usedLanguages = [ { id: 1, lang: 'EN' } ] 生成新数组的最快方法是什么?这两种方法的区别是什么?在旧式JavaScript中,您必须在另一个for循环中执行for循环,我认为 例如: 您可以使用filter()和find()返回过滤后的数组 const allLanguages=['ES','EN','DE'] const usedLan

所以我有两个数组:

const allLanguages = [ 'ES', 'EN', 'DE' ]
const usedLanguages = [ { id: 1, lang: 'EN' } ]
生成新数组的最快方法是什么?这两种方法的区别是什么?在旧式JavaScript中,您必须在另一个for循环中执行for循环,我认为

例如:

您可以使用
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(结果)
您可以使用以下代码:

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

some
函数相对于
find
是一个鲜为人知的函数,它更适合于检查数组中至少一个元素是否满足条件的情况。

使用
数组#reduce
迭代
使用的语言
,以
新集(所有语言)
作为起始值。从每次迭代时设置的
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、 删除(lang);
返回r;
},新设置(所有语言))];
控制台日志(结果)基于集合的方法
受@Ori Drori出色答案的启发,这里是一个纯粹的基于集合的解决方案

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

const availableLanguages = setDifference(all, used);
在哪里

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#has
O(1)
,但与
find
some
O(n)
相比,总体性能仍然是
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
循环:-):


嘿,是你说你想用ES6的。

你可能想用它来代替
。find()
,这样就不会有愚蠢的错误。
一些
短路的方式与
find
@4是的,我错了,它们的区别在于输出而不是性能。@torazaburo我指的是
find
返回的值的错误。在这种情况下,对象永远不会是错误的,但通常情况下,类型合并是不必要的,如果情况不同,则可能出现错误。@shai我不同意“不幸”一词与Internet Explorer不兼容的说法。仅仅通过设计和意图或最快的运行时性能,它与标准不兼容?如果这真的是你的目标——换句话说,这段代码执行了数百万次,对你的应用程序来说是至关重要的——那么你最好为循环编写一些
。这是我一生的命运。我汇集了我微薄的ES6知识来提供答案,唯一的回答是来自一个loops的家伙:)你使用了扩展运算符、集合、箭头函数和分解结构,但你忽略了承诺、代理、类和生成器。:-)正如我所说的“我微薄的ES6知识”。然而,我决定忏悔!不要了!我将使用循环!我要向大师学习。想象一下,当我发现这一点时,我感到震惊和沮丧——我觉得我的教育已经完成:)喜欢创建字典的神秘方式。字典方法可以通过使用
对象来改进。为空对象创建(null)
,这样
对象。原型
中的内容不会给出误报。
const dict = usedLanguages.reduce((obj, {lang}) => {
  obj[lang] = true;
  return obj;
}, {});
const dict = usedLanguages.reduce((obj, {lang}) => (obj[lang] = true, obj), {});
const dict = {};
for (x of usedLanguages) {
  dict[x.lang] = true;
}