简体   繁体   English

是否有任何方法与map()执行相同的操作但生成不同类型的容器?

[英]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方法然后再调用toListtoListtoList ,但这会产生一个冗余的中间集合。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM