在集合上应用链式筛选器

huangapple go评论54阅读模式
英文:

Apply chained filters on a collection

问题

我有一个Scala类实例的序列 -

val vehicles = Seq[Vehicle]
  
class Vehicle(name:String, model:String, age:Int, color:String)
{...}

现在我需要将这个序列通过一系列的过滤器传递 - 每个过滤器都过滤特定的属性。

List[Vehicle].filter(_.name.startsWith("J")).filter(_.model.contains("Toy:)).....

由于每个过滤条件都很复杂,我需要将它们封装在一个函数中。

在Scala中是否有一种方法可以在集合上应用自定义函数,例如 List[Vehicle].applyfilterchain(params),以返回最终过滤后的集合。

英文:

I have a sequence of a scala class instances -

val vehicles = Seq[Vehicle]

class Vehicle(name:String, model:String, age:Int, color:String )
{...}

Now I need to pass this sequence through a chain of filters - each filtering for a specific attribute.

List[Vehicle].filter(_.name.startsWith("J")).filter(_.model.contains("Toy:)).....

Since each of these filter conditions are complex , I need to encapsulate them in a function.

Is there a way in scala to apply a custom function on a collection viz List[Vehicle].applyfilterchain(params) , to return the final filtered collection.

答案1

得分: 2

这是一个关于“playing type-tetris”的很好练习。

所以,我们想要对列表的所有元素应用多个谓词,这给出了函数的签名。

def filterChain[A](list: List[A])(predicates: List[A => Boolean]): List[A]

这是可能的,因为在Scala中,函数只是普通值,所以我们可以有一个它们的List

现在,对于实现,有两种路线可以选择。

  1. 迭代谓词,逐个应用它们到列表上。
  2. 一次迭代列表,将所有谓词应用到相同的元素上。

两者都可行,但快速的复杂性分析显示第二种方法更好。

第一种的实现留给读者作为练习。
提示:使用foldLeft

因此,我们知道我们要在List上使用filter来开始我们的实现。

def filterChain[A](list: List[A])(predicates: List[A => Boolean]): List[A] =
  list.filter(a => ???)

现在,我们知道lambda的主体必须返回一个Boolean
我们还知道我们有类型为Aa,以及类型为List[A => Boolean]predicates
因此,我们可以将predicates中的每个函数应用于a,然后我们想知道是否全部成功。
这正是forall允许的内容。

a => predicates.forall(predicate => predicate(a))

将所有内容放在一起:https://scastie.scala-lang.org/BalmungSan/W5k9KCZKRj6XN71tompZfw/6

英文:

This is a great excercise for "playing type-tetris".

So, we want to apply multiple predicates to all elements of a list, so that gives the signature of the function.

def filterChain[A](list: List[A])(predicates: List[A => Boolean]): List[A]

> This is possible because in Scala functions are just normal values, so we can have a List of them.

Now, for the implementation, there are two routes we may follow.

  1. Iterate the predicates, applying them to the list one by one.
  2. Iterate the list once, applying all predicates to the same element.

Both are applicable, but a quick complexity analysis shows is better to do the second one.

> The implementation of the first one is left as an exercise for the reader.<br>
> Hint: Use foldLeft.

Thus, we know we want to start our implementation using filter on the List.

def filterChain[A](list: List[A])(predicates: List[A =&gt; Boolean]): List[A] =
  list.filter(a =&gt; ???)

Now, we know the body of the lambda has to return a Boolean.
We also know that we have a of type A, and predicates of type List[A =&gt; Boolean]<br>
Thus, we know we may apply each function inside predicates to a, and then we want to know if all succeded. That is exactly what forall allows.

a =&gt; predicates.forall(predicate =&gt; predicate(a))

Putting it all together: https://scastie.scala-lang.org/BalmungSan/W5k9KCZKRj6XN71tompZfw/6

答案2

得分: 0

这可以实现为一个常规方法:

def applyfilterchain(params...)(seq: Seq[Vehicle]) = {
  seq.filter(...).filter(...)
}

// 然后:
applyfilterchain(...)(vehicles)

或者如果你真的想要的话,你可以将其定义为一个扩展方法(在Scala 2中也称为隐式类),这样可以像以下这样调用它:vehicles.applyfilterchain(...).

英文:

It can be implemented as a regular method:

def applyfilterchain(params...)(seq: Seq[Vehicle]) = {
  seq.filter(...).filter(...)
}

// And then:
applyfilterchain(...)(vehicles)

Or if you really want to, you can define it as an extension method (also called implicit class in Scala 2) so that it can be called like the following: vehicles.applyfilterchain(...).

huangapple
  • 本文由 发表于 2023年6月30日 00:06:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76582803.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定