2016-03-23 56 views
3

我有2所列出:加入不等長度兩個列表中斯卡拉

val list_1 = List((1, 11), (2, 12), (3, 13), (4, 14)) 
val list_2 = List((1, 111), (2, 122), (3, 133), (4, 144), (1, 123), (2, 234)) 

我想在第二個列表的第一個列表的值替換鍵,導致一個新的列表,看起來像:

List ((11, 111), (12, 122), (13, 133), (14, 144), (11, 123), (12, 234)) 

這是我的嘗試:

object UniqueTest { 
    def main(args: Array[String]){ 
    val l_1 = List((1, 11), (2, 12), (3, 13), (4, 14)) 
    val l_2 = List((1, 111), (2,122), (3, 133), (4, 144), (1, 123), (2, 234)) 
    val l_3 = l_2.map(x => (f(x._1, l_1), x._2)) 
    print(l_3) 

    } 
    def f(i: Int, list: List[(Int, Int)]): Int = { 
    for(pair <- list){ 
     if(i == pair._1){ 
     return pair._2 
     } 
    } 
    return 0 
    } 
} 

這導致:

((11, 111), (12, 122), (13, 133), (14, 144), (11, 123), (12, 234)) 

上面的程序是一個很好的方法來做到這一點? Scala中是否有內置函數來處理這種需求,或者另一種方式來處理這種操作?

回答

4

唯一真正的過度複雜,你提出的是這一行:

val l_3 = l_2.map(x => (f(x._1, l_1), x._2)) 

您的f函數使用命令式風格來循環ove找一個關鍵的列表。任何時候你發現自己這樣做,這是一個很好的指示你想要的是一個map。通過在每次爆炸計算複雜度時執行for循環:地圖將允許您獲取O(1)中給定鍵的相應值。通過映射,您可以首先將您的列表(鍵值對)轉換爲明確支持鍵值對關係的數據結構。

因此,你應該做的第一件事就是建立你的地圖。斯卡拉提供了一個非常簡單的方法與toMap做到這一點:

val map_1 = list_1.toMap 

然後,它僅僅是一個「映射」的事:

val result = list_2.map { case (key, value) => map_1.getOrElse(key, 0), value) } 

這需要每種情況下,你的list_2,匹配的第一個值( key)添加到您的map_1中的密鑰中,檢索該值(或默認0),並將其作爲鍵值元組中的第一個值。

2

你可以這樣做:

val map = l_1.toMap   // transform l_1 to a Map[Int, Int] 
// for each (a, b) in l_2, retrieve the new value v of a and return (v, b) 
val res = l_2.map { case (a, b) => (map.getOrElse(a, 0), b) } 
+0

非常感謝。你可以在.map之後告訴我「{}」和「()」之間的區別嗎?有時,我可以在.map之後使用圓括號,但是對於這個「()」會給我編譯器錯誤。 – Frankie

+0

我在這種情況下使用了''{}'',所以我可以使用模式匹配即''case(a,b)=> ...'' –

+0

在元組列表上應用'toMap'有風險:元組,如果數據集中有重複的第一個元素。 – Roman

0

最慣用的方法是一起荏苒他們,然後轉化根據您的需求:

(list_1 zip list_2) map { case ((k1, v1), (k2, v2)) => (v1, v2) } 
+1

當列表長度不等時,這不起作用,請嘗試問題中列出的示例。 – helios35

+0

啊,我錯過了這個列表的長度不同。該方法可以調整,也不會那麼優雅。例如,如果第一個列表更短,我們可以執行'(list_1 ::: list_1 zip list_2)'。 – Roman