2016-03-23 53 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