簡體   English   中英

Scala中的完全外部聯接

[英]Full outer join in Scala

給定一個列表列表,其中每個列表都有一個代表鍵的對象,我需要編寫一個完整的外部聯接來組合所有列表。 結果列表中的每個記錄都是所有列表的所有字段的組合。 如果一個鍵存在於列表1中而不存在於列表2中,則列表2中的字段應為null或為空。

我想到的一種解決方案是嵌入一個內存數據庫,創建表,運行選擇並獲得結果。 但是,我想知道是否有任何庫可以更簡單地處理此問題。 有任何想法嗎?

例如,假設我有兩個列表,其中鍵是列表中的第一個字段:

val list1 = List ((1,2), (3,4), (5,6))
val list2 = List ((1,"A"), (7,"B"))
val allLists = List (list1, list2)

完整的外部連接列表為:

val allListsJoined = List ((1,2,"A"), (3,4,None), (5,6,None), (7,None,"B"))

注意:該解決方案需要適用於N個列表

def fullOuterJoin[K, V1, V2](xs: List[(K, V1)], ys: List[(K, V2)]): List[(K, Option[V1], Option[V2])] = {
  val map1 = xs.toMap
  val map2 = ys.toMap
  val allKeys = map1.keySet ++ map2.keySet
  allKeys.toList.map(k => (k, map1.get(k), map2.get(k)))
}

用法示例:

val list1 = List ((1,2), (3,4), (5,6))
val list2 = List ((1,"A"), (7,"B"))
println(fullOuterJoin(list1, list2))

哪些打印:

List((1,Some(2),Some(A)), (3,Some(4),None), (5,Some(6),None), (7,None,Some(B)))

根據評論中的建議進行編輯:

如果您有興趣加入任意數量的列表,並且不關心類型信息,則可以使用以下版本:

def fullOuterJoin[K](xs: List[List[(K, Any)]]): List[(K, List[Option[Any]])] = {
  val maps = xs.map(_.toMap)
  val allKeys = maps.map(_.keySet).reduce(_ ++ _)
  allKeys.toList.map(k => (k, maps.map(m => m.get(k))))
}

val list1 = List ((1,2), (3,4), (5,6))
val list2 = List ((1,"A"), (7,"B"))
val list3 = List((1, 3.5), (7, 4.0))
val lists = List(list1, list2, list3)
println(fullOuterJoin(lists))

輸出:

List((1,List(Some(2), Some(A), Some(3.5))), (3,List(Some(4), None, None)), (5,List(Some(6), None, None)), (7,List(None, Some(B), Some(4.0))))

如果您想要任意數量的列表和類型正確的結果,這可能超出了stackoverflow答案的范圍,但可能可以通過無形來實現

這是在兩個列表上單獨使用collect一種方法

val list1Ite =  list1.collect{
  case ele if list2.filter(e=> e._1 == ele._1).size>0 => { //if list2 _1 contains ele._1
     val left = list2.find(e=> e._1 == ele._1) //find the available element
     (ele._1, ele._2, left.get._2) //perform join
  }
  case others => (others._1, others._2, None) //others add None as _3 
}
//list1Ite: List[(Int, Int, java.io.Serializable)] = List((1,2,A), (3,4,None), (5,6,None))

進行類似的操作,但排除list1Ite中已經可用的list1Ite

val list2Ite = list2.collect{
  case ele if list1.filter(e=> e._1 == ele._1).size==0 => (ele._1, None , ele._2)
}
//list2Ite: List[(Int, None.type, String)] = List((7,None,B))

list1Itelist2Ite合並為result

val result = list1Ite.++(list2Ite)

result: List[(Int, Any, java.io.Serializable)] = List((1,2,A), (3,4,None), (5,6,None), (7,None,B))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM