英文:
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
。
现在,对于实现,有两种路线可以选择。
- 迭代谓词,逐个应用它们到列表上。
- 一次迭代列表,将所有谓词应用到相同的元素上。
两者都可行,但快速的复杂性分析显示第二种方法更好。
第一种的实现留给读者作为练习。
提示:使用foldLeft
。
因此,我们知道我们要在List
上使用filter
来开始我们的实现。
def filterChain[A](list: List[A])(predicates: List[A => Boolean]): List[A] =
list.filter(a => ???)
现在,我们知道lambda的主体必须返回一个Boolean
。
我们还知道我们有类型为A
的a
,以及类型为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.
- Iterate the predicates, applying them to the list one by one.
- 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 => Boolean]): List[A] =
list.filter(a => ???)
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 => 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 => predicates.forall(predicate => 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(...)
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论