有时我需要通过映射另一个具有不同类型的集合来创建集合。例如,某些函数需要List[_]
作为其参数类型,但我需要通过映射IndexedSeq[_]
来生成它:
val r = (1 to n).map { ... }
someFunction(r.toList)
虽然我可以通过首先调用IndexedSeq[_]
的{{1}}方法然后再调用map
来实现这一点,但这会产生一个冗余的中间集合。有没有办法避免这个冗余的步骤,同时仍然保持代码简洁?
答案 0 :(得分:9)
查看map
的完整签名:
def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[List[A], B, That]): That
这个的关键是隐式CanBuildFrom
,它控制从输入集合生成结果集合的方式。我们可以用一个允许我们构建不同结果集合的显式CanBuildFrom
替换隐式scala.collection.breakOut
。
更好的是,我们甚至不必编写这种显式方法!它已经以collection.breakOut
的形式出现了。来自ScalaDoc:
提供一个CanBuildFrom实例,用于构建特定目标集合(To'),而不管原始集合(From')。
因此,如果我们传入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)
方法的要求:
{{1}}
答案 1 :(得分:3)
你的问题的答案是collection.breakOut
,正如om-nom-nom在他的评论中所述。
breakOut
是map
方法的附加参数,并且 - 为了简单起见 - 它允许从map
返回不同类型的集合:
def directMapExample(seq: Seq[Int]): Set[Int] = seq.map(_ * 2)(collection.breakOut)
请注意,以下内容在编译时失败:
def directMapExample2(seq: Seq[Int]): Set[Int] = seq.map(_ * 2)
有关详细信息,请参阅https://stackoverflow.com/a/1716558/298389。
答案 2 :(得分:0)
使用视图可能有帮助吗?
val r = (1 to n).view.map { … }
someFunction(r.toList)
map
函数是Range
上的严格转换。但是,如果首先将其转换为视图,那么Range
(这是一个非严格的集合)将被包装在以非严格方式实现map
的对象中。只有在调用toList
时才会生成全部值。