使用多个测试条件和filter方法筛选对象数组

3

我想根据多个条件过滤对象数组。举个例子,如果某些键的值不是空的并且一个键的值小于90,则希望对对象数组进行过滤。目前,我正在使用for循环进行过滤,如下所示:

let filtered = []
for (let i = 0; i < articles.length; i++) {
    if (articles[i].title !== null && articles[i].title.length <= 90 &&
        articles[i].date !== null &&
        articles[i].image !== null &&
        articles[i].description !== null &&
        articles[i].link !== null) {
        filtered.push(articles[i])
    }
}

但是它相当笨重,我知道filter方法可以实现类似的功能。但我不确定它是否可以检查多个键和它们的值使用相同的测试,同时检查特定值是否通过独立测试。

3个回答

6

尝试:

articles.filter(article => 
  Object.values(article).every(x => (x !== null))
  && article.title.length <= 90
) 

让我们分解一下:

articles.filter(article => ...) 

.filter是一种函数属性类型,接受一个回调参数,对于每个项目都会调用它。本质上,我们正在传递函数 - 而不是立即执行它,它可以在适当的时候调用它。这有点像:

let a = alert;

我们并没有调用 alert 函数,只是将它保存在一个变量中。对于 .filter,我们将其用作伪变量 - 一个参数。在内部,所有的 .filter 实际上只是:
Array.prototype.filter(callbackFunc) {
    newArr = [];
    for (i=0;i<this.length;i++){
        if (callbackFunc(this[i]) === false){  // We're calling `callbackFunc` manually, for each item in the loop.
            newArr.push(this[i]);
        }
    }

    return newArr;
}

下一个需要解释的部分是我们正在使用的实际回调函数。它是使用ES6箭头语法定义的,但它等效于:
articles.filter(function(article){
  return Object.values(article).every(x => (x !== null))
  && article.title.length <= 90
}) 

回调函数的第一行 Object.values(article).every(x => (x !== null)),可以拆分为:
let values = Object.values(article); // Get the value of all of the keys in the object

function checkFunction(item){ // Define a helper function
    return (x !== null); // Which returns if an item is _not_ null.
}

let result = values.every(checkFunction); // Run `checkFunction` on every item in the array (see below), and ensure it matches _all_ of them.

最后,我们只需要澄清一下every的作用。这是另一个函数式JS的例子,其中函数接受回调函数作为参数。内部代码如下:

Array.prototype.every(callbackFunc) {
    for (i=0;i<this.length;i++){
        if (callbackFunc(this[i]) === false){  // We're calling `callbackFunc` manually, for each item in the loop.
            return false;
        }
    }
    // In JS, returning a value automatically stops execution of the function.
    // So this line of code is only reached if `return false` is never met.
    return true;
}

"

&& article.title.length <= 90 应该很容易理解:当 .every 返回一个布尔值 (truefalse),只有当回调函数同时满足第二个条件时,才会将 true 返回到 filter 中,即如果 every 返回 true 并且 article.title.length <= 90

"

可能是最可扩展和最干净的答案!这是一个不错的选择 :) - Matthew Liu
你为什么使用了 some 方法而不是 every - fellinlovewithaman
1
我现在正在为@fellinlovewithaman准备一份解释,我只是想先做好FGIW。 - Geza Kerecsenyi
1
@fellinlovewithaman 噢,非常好的发现 - 根据您的原始代码,我认为应该使用 every,因为 some 只需要至少一个“真值”,而您想要所有值都是“真值”。 - Matthew Liu
@MatthewLiu 确定,已修复。 - Geza Kerecsenyi
@fellinlovewithaman 我现在添加了一个解释,希望它是函数式JS的好介绍! - Geza Kerecsenyi

2
< p > filter 方法正是这样做的:它接受一个条件(就像你if语句中的那个)并在满足条件时将其添加到数组中。实际上,您的代码几乎与filter语法完全匹配:


let filtered = articles.filter(article =>
  article.title !== null
  article.title.length <= 90 &&
  article.date !== null &&
  article.image !== null &&
  article.description !== null &&
  article.link !== null);

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接