[英]Is there any method that does the same thing as map() but generates a different type of container?
Sometimes I need to create a collection by mapping another one with different type. 有时我需要通过映射另一个具有不同类型的集合来创建集合。 For example, some function needs List[_]
as its parameter type, but I need to produce that by mapping a IndexedSeq[_]
: 例如,某些函数需要List[_]
作为其参数类型,但我需要通过映射IndexedSeq[_]
来生成它:
val r = (1 to n).map { ... }
someFunction(r.toList)
Although I can fulfill that by calling IndexedSeq[_]
's map
method first followed by another call to toList
, this produces a redundant intermediate collection. 虽然我可以通过首先调用IndexedSeq[_]
的map
方法然后再调用toList
来toList
这toList
,但这会产生一个冗余的中间集合。 Is there any way to avoid this redundant step while still keeping code concise? 有什么方法可以避免这个冗余的步骤,同时仍然保持代码简洁?
Have a look at the full signature for map
: 看看map
的完整签名:
def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[List[A], B, That]): That
The key to this is the implicit CanBuildFrom
, which governs how the result collection is generated from the input collection. 关键是隐式CanBuildFrom
,它控制如何从输入集合生成结果集合。 We can replace the implicit CanBuildFrom
with an explicit one that allows us to build a different result collection. 我们可以使用允许我们构建不同结果集合的显式CanBuildFrom
替换隐式CanBuildFrom
。
Even better, we don't even have to write this explicit method! 更好的是,我们甚至不必编写这种显式方法! It's there already, in the form of scala.collection.breakOut
. 它已经以scala.collection.breakOut
的形式出现了。 From the ScalaDoc: 来自ScalaDoc:
Provides a CanBuildFrom instance that builds a specific target collection (To') irrespective of the original collection (From'). 提供CanBuildFrom实例,该实例构建特定目标集合(To'),而不管原始集合(From')。
So if we pass in collection.breakOut
, we can then specify exactly what we want to the map
method: 因此,如果我们传入collection.breakOut
,我们就可以准确地指定我们想要的map
方法:
val x = IndexedSeq(1,2,3,4,5)
x.map[Int, List[Int]](_ * 2)(collection.breakOut)
> res6: List[Int] = List(2, 4, 6, 8, 10)
The answer to your question is collection.breakOut
, as stated by om-nom-nom in his comment. 你的问题的答案是collection.breakOut
,正如om-nom-nom在他的评论中所述。
breakOut
is an additional argument given to the map
method, and - to keep it simple - it allows to return different types of collections from map
: breakOut
是一个给map
方法的附加参数,并且 - 为了简单breakOut
- 它允许从map
返回不同类型的集合:
def directMapExample(seq: Seq[Int]): Set[Int] = seq.map(_ * 2)(collection.breakOut)
Note, that the following fails at compilation: 请注意,以下内容在编译时失败:
def directMapExample2(seq: Seq[Int]): Set[Int] = seq.map(_ * 2)
For details, see https://stackoverflow.com/a/1716558/298389 . 有关详细信息,请参阅https://stackoverflow.com/a/1716558/298389 。
Using a view might help? 使用视图可能有帮助吗?
val r = (1 to n).view.map { … }
someFunction(r.toList)
The map
function is a strict transformer on Range
. map
函数是Range
上的严格变换器。 However, if you turn it into a view first, then that Range
(which is a non-strict collection) will be wrapped inside an object that implements map
in a non-strict way. 但是,如果首先将其转换为视图,那么该Range
(这是一个非严格的集合)将被包装在一个以非严格方式实现map
的对象中。 The full range of values would only be produced when calling toList
. 只有在调用toList
时才会产生全部值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.