2015-01-13 213 views
2

我有一个像这样与各种类型的列表:斯卡拉 - 扩大不同类型的列表,同时保持相同类型

val data: List[(String, Int, List[String])] = List(("foo", 1, List("a", "b")), ("bar", 2, List("c", "d")), ("baz", 1, List("e", "f")))

那里有一个int值比1大,我试图复制在这个范围内(从1到智力)的项目每个诠释 - 所以最好将看起来像(强调的是,诠释需要递增从1每个迭代INT):

val dataExpanded: List[(String, Int, List[String])] = List(("foo", 1, List("a", "b")), ("bar", 1, List("c", "d")), ("bar", 2, List("c", "d")), ("baz", 1, List("e", "f")))

在scala中处理类型常常会让我头疼,特别是嵌套结构,因为每个操作似乎都会引入越来越多类型的陷阱。

所以虽然我想:

val dataExpanded = data.map{ case (s, i, l) => 

    if (i > 1) { 

     List.range(1, i+1).map { n => 
      (s, n, l) 
     } 

    } else { 
     (s, i, l) 
    } 
} 

我得到的结果是:

> dataExpanded: List[Product with java.io.Serializable] = List((foo,1,List(a, b)), List((bar,1,List(c, d)), (bar,2,List(c, d))), (baz,1,List(e, f)))

结果看起来是在正确的道路上,但扩展元素嵌套在其自己的名单,结果,我认为,类型是错误的。没有多少flatMapping或flattening或映射的for循环的输出是让我走出这堵塞。

这也可能与我的病例陈述并没有处理无病例,但我不知道如何处理其他病例(我知道这是不正确的说,但我不会真的有任何其他病例我的数据案例 - 虽然这是动态类型的语言说话醉)

当从datadataExpanded时,有没有一种方法来保持预期的类型,同时避免不必要的循环?

+0

的问题是,所述类型是的如果/其他两个分支的不同(与[严格编译器参数](http://tpolecat.github.io/ 2014/04/11/scalac-flags.html)这将是一个错误,这可能会帮助你找到问题)。你可以使'else'分支'List((s,i,l))',然后你只需要'变平'。虽然从建议中可以看出,你根本不需要'if' /'else' - 即使在'i = 1'时,'if'分支中的代码也能正常工作。 – lmm

回答

1

你被关闭,你可以做

val dataExpanded = data.flatMap { 
case (s, i, l) => 
    List.range(1, i + 1).map { n => 
    (s, n, l) 
    } 
}            

//> dataExpanded : List[(String, Int, List[String])] = List((foo,1,List(a, b)), 
         (bar,1,List(c, d)), (bar,2,List(c, d)), (baz,1,List(e, f))) 

或者更整齐的

val dataExpanded = data.flatMap { 
    case (s, i, l) => 
     (1 to i).map ((s, _, l)) 
    }            
6

考虑为元组的情况下的类,像这样

case class Datum(s: String, n: Int, xs: List[String]) 

并因此给出

val data: List[Datum] = List(Datum("foo", 1, List("a", "b")), 
          Datum("bar", 2, List("c", "d")), 
          Datum("baz", 1, List("e", "f"))) 

我们可以使用copy方法的情况下,类如下,

def expand(d: Datum) = (1 to d.n).map (i => d.copy(n=i)) 

副本字段内容和修改指定的字段,在这种情况下为n。因此,对于data,

data.flatMap(expand(_)) 

提供期望的输出。

0

比@enzyme答案有点冗长,但这里是递归,模式匹配的方法,并a表达式来生成元组。

def expand(xs: List[Tuple3[String, Int, List[String]]]): List[Tuple3[String,Int, List[String]]] = xs match { 
case Nil => Nil 
case h :: t => if (h._2 == 1) 
        h :: expand(t) 
       else 
        (for(i <- 1 to h._2) yield (h._1, i, h._3)).toList ++ expand(t) 
} 

输出:

scala> expand(data) 
List[(String, Int, List[String])] = List((foo,1,List(a, b)), (bar,1,List(c, d)), (bar,2,List(c, d)), (baz,1,List(e, f)))