2017-09-25 73 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]的頂部,如果你想轉換或轉換爲不同的數據類型那麼無論你需要隱式還是明確地施放它。