2017-09-25 74 views
1

设置我有类Set[String]类型的字段。另外,我有这个类的对象列表。我想将所有这些对象集合中的所有字符串收集到一个集合中。这是我如何能做到这一点已经:斯卡拉:使用列表中flatMap

case class MyClass(field: Set[String]) 

val list = List(
    MyClass(Set("123")), 
    MyClass(Set("456", "798")), 
    MyClass(Set("123", "798")) 
) 

list.flatMap(_.field).toSet // Set(123, 456, 798) 

它的工作原理,但我想,我可以只使用flatMap达到同样的,没有toSet调用。我想这一点,但它给了编译错误:

// error: Cannot construct a collection of type Set[String] 
// with elements of type String based on a collection of type List[MyClass]. 
list.flatMap[String, Set[String]](_.field) 

如果我改变的listSet类型(即val list = Set(...)),那么这样的flatMap调用工作。

所以,我可以用某种方式Set.canBuildFrom或任何其他CanBuildFrom对象调用flatMapList对象,这样我会得到Set结果?

回答

5

你想要的CanBuildFrom实例被称为breakOut和必须提供的第二个参数:

import scala.collection.breakOut 

case class MyClass(field: Set[String]) 

val list = List(
    MyClass(Set("123")), 
    MyClass(Set("456", "798")), 
    MyClass(Set("123", "798")) 
) 

val s: Set[String] = list.flatMap(_.field)(breakOut) 

需要注意的是可变s显式类型注解是必须的 - 这是类型是如何选择的。

编辑:

如果您使用Scalazcats,您可以使用foldMap还有:

import scalaz._, Scalaz._ 
list.foldMap(_.field) 

这确实基本上就是mdm的回答提出,除了Set.empty++零件已经被烘烤了。

1

也许你可以提供一个特定的CanBuildFrom,但为什么不使用倍呢?

list.foldLeft(Set.empty[String]){case (set, myClass) => set ++ myClass.field} 

仍然只是一次通过收集,如果你确信list不是空的,你甚至可以用户reduceLeft代替。

+0

因为'foldLeft'接受函数,所以在这里不需要使用'case'两个参数,即'(_ ++ _.field)' –

+0

你当然是正确的@Oneg,但为了清晰起见,我明确表示。 – mdm

+0

您仍然可以省略“case”关键字,因为您没有进行任何重要的模式匹配 –

4

斯卡拉方式flatMap工作是,它只能删除一个包装相同类型的包装即List[List[String]] -> flatMap -> List[String]

如果您在不同包装的数据类型的应用flatMap那么你总是会得到的最终结果为更高层次包装数据类型即List[Set[String]] -> flatMap -> List[String]

,如果你要申请不同的包装类型,即List[Set[String]] -> flatMap -> Set[String]的flatMap你有2个选择: -

  1. Explicitl ÿ投所述一个数据类型包装到另一个即list.flatMap(_.field).toSet

  2. 通过提供隐式转换器即implicit def listToSet(list: List[String]): Set[String] = list.toSet和你可以得到val set:Set[String] = list.flatMap(_.field)

才把你正在努力实现将完成什么。

结论: -如果您在2包装的数据类型适用flatMap那么你总是会得到的最终结果为运算类型,是在包装的数据类型,即List[Set[String]] -> flatMap -> List[String]的顶部,如果你想转换或转换为不同的数据类型那么无论你需要隐式还是明确地施放它。