Scala分区/收集用法 [英] Scala Partition/Collect Usage
问题描述
是否可以使用一个呼叫collect
来创建2个新列表?如果没有,该如何使用partition
做到这一点?
Is it possible to use one call to collect
to make 2 new lists? If not, how can I do this using partition
?
推荐答案
collect
(在 Scala语言规范 [警告-PDF] )
collect
(defined on TraversableLike and available in all subclasses) works with a collection and a PartialFunction
. It also just so happens that a bunch of case clauses defined inside braces are a partial function (See section 8.5 of the Scala Language Specification [warning - PDF])
与异常处理一样:
try {
... do something risky ...
} catch {
//The contents of this catch block are a partial function
case e: IOException => ...
case e: OtherException => ...
}
这是一种定义仅接受某些给定类型值的函数的简便方法.
It's a handy way to define a function that will only accept some values of a given type.
考虑在混合值列表上使用它:
Consider using it on a list of mixed values:
val mixedList = List("a", 1, 2, "b", 19, 42.0) //this is a List[Any]
val results = mixedList collect {
case s: String => "String:" + s
case i: Int => "Int:" + i.toString
}
collect
方法的参数是PartialFunction[Any,String]
. PartialFunction
因为未为Any
类型(即List
的类型)和String
的所有可能输入定义它,因为这是所有子句返回的内容.
The argument to to collect
method is a PartialFunction[Any,String]
. PartialFunction
because it's not defined for all possible inputs of type Any
(that being the type of the List
) and String
because that's what all the clauses return.
如果尝试使用map
而不是collect
,则mixedList
末尾的double值将导致MatchError
.使用collect
会丢弃该值以及未定义PartialFunction的任何其他值.
If you tried to use map
instead of collect
, the the double value at the end of mixedList
would cause a MatchError
. Using collect
just discards this, as well as any other value for which the PartialFunction is not defined.
一种可能的用途是将不同的逻辑应用于列表的元素:
One possible use would be to apply different logic to elements of the list:
var strings = List.empty[String]
var ints = List.empty[Int]
mixedList collect {
case s: String => strings :+= s
case i: Int => ints :+= i
}
尽管这只是一个例子,但使用可变变量这样的变量被许多人视为战争罪-所以请不要这样做!
Although this is just an example, using mutable variables like this is considered by many to be a war crime - So please don't do it!
很多更好的解决方案是使用两次收集:
A much better solution is to use collect twice:
val strings = mixedList collect { case s: String => s }
val ints = mixedList collect { case i: Int => i }
或者,如果您确定该列表仅包含两种类型的值,则可以使用partition
,它会根据集合是否与某些谓词匹配来将集合拆分为值:
Or if you know for certain that the list only contains two types of values, you can use partition
, which splits a collections into values depending on whether or not they match some predicate:
//if the list only contains Strings and Ints:
val (strings, ints) = mixedList partition { case s: String => true; case _ => false }
这里的要点是strings
和ints
都是List[Any]
类型,尽管您可以轻松地将它们强制返回为更安全的类型(也许通过使用collect
...)
The catch here is that both strings
and ints
are of type List[Any]
, though you can easily coerce them back to something more typesafe (perhaps by using collect
...)
如果您已经有一个类型安全的集合,并且想对元素的其他属性进行拆分,那么事情对您来说会容易一些:
If you already have a type-safe collection and want to split on some other property of the elements, then things are a bit easier for you:
val intList = List(2,7,9,1,6,5,8,2,4,6,2,9,8)
val (big,small) = intList partition (_ > 5)
//big and small are both now List[Int]s
希望总结一下这两种方法如何为您提供帮助!
Hope that sums up how the two methods can help you out here!
这篇关于Scala分区/收集用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!