在ES6中获取不同的阵列?

j_d*_*j_d 15 javascript arrays ecmascript-6

所以我有两个数组:

const allLanguages = [ 'ES', 'EN', 'DE' ]
const usedLanguages = [ { id: 1, lang: 'EN' } ]
Run Code Online (Sandbox Code Playgroud)

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

例如:

const availableLanguages = [ 'ES', 'DE' ]
Run Code Online (Sandbox Code Playgroud)

Nen*_*car 24

您可以使用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)
Run Code Online (Sandbox Code Playgroud)

您还可以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)
Run Code Online (Sandbox Code Playgroud)

  • 您可能希望使用[`.some()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some)而不是`.find()` ,所以没有虚假的foolery. (4认同)
  • @torazaburo我指的是`find`返回的值的虚假性。在这种情况下,一个对象永远不会虚假,但是通常情况下,类型强制是不必要的,并且在情况不同的情况下容易出现错误。 (2认同)

小智 9

基于集合的方法

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

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

const availableLanguages = setDifference(all, used);
Run Code Online (Sandbox Code Playgroud)

哪里

const setDifference = (a, b) => new Set([...a].filter(x => !b.has(x)));
Run Code Online (Sandbox Code Playgroud)

availableLanguages将是一个集合,因此要将其作为数组使用,您需要对其进行处理Array.from[...map]对其进行处理。

如果想让所有功能正常运行,那么

const not = fn => x => !fn(x);
const isIn = set => x => set.has(x);
Run Code Online (Sandbox Code Playgroud)

现在写

const setDifference = (a, b) => new Set([...a].filter(not(isIn(b))));
Run Code Online (Sandbox Code Playgroud)

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

但是,这些解决方案并不令人满意,并且可能不是最佳的。即使Set#hasO(1),相比O(n)findsome,整体表现依然O(n),因为我们经历的所有元素都具有迭代a。这将是更好的删除元素ba,因为有人建议在另一个答案。这是

const setDifference = (a, b) => {
  const result = new Set(a);
  b.forEach(x => result.delete(x));
  return result;
}
Run Code Online (Sandbox Code Playgroud)

我们不能使用它,reduce因为它在集合上不可用,并且我们不想将集合转换为数组来使用它。但是我们可以使用forEach,它在设备上可用。如果a较大且b较小,则该替代方案将是优选的。

将来的JS版本很可能会内置此功能,您可以说

const availableLanguages = all.difference(used)
Run Code Online (Sandbox Code Playgroud)

基于生成器的方法

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

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

现在我们可以写

console.log([...difference(allLanguages, usedLanguages)]);
Run Code Online (Sandbox Code Playgroud)

如果有很长的语言列表,也许是一种一一出现,并且您想获得一小部分未使用的语言,则可能建议使用此解决方案。

使用字典

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

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

const availableLanguages = allLanguages.filter(lang => lang in dict);
Run Code Online (Sandbox Code Playgroud)

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

const dict = usedLanguages.reduce((obj, {lang}) => {
  obj[lang] = true;
  return obj;
}, {});
Run Code Online (Sandbox Code Playgroud)

Nina喜欢用逗号运算符写成

const dict = usedLanguages.reduce((obj, {lang}) => (obj[lang] = true, obj), {});
Run Code Online (Sandbox Code Playgroud)

这样可以节省一些花括号。

或者,由于JS仍然有for循环:-):

const dict = {};
for (x of usedLanguages) {
  dict[x.lang] = true;
}
Run Code Online (Sandbox Code Playgroud)

嗨,您是谁说过要使用ES6的人。


Sha*_*hai 6

您可以使用以下代码:

availableLanguages = allLanguages.filter((lang1) => !usedLanguages.some((lang2) => lang2.lang === lang1))
Run Code Online (Sandbox Code Playgroud)

some函数相对于此更为人所知find,更适合于您要检查数组中是否满足条件的情况.