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,我试图为该范围内的每个 Int 复制这些项目(从 1 到 Int) - 所以理想情况下它看起来像(强调每次迭代需要从 1 递增 Int到 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 或扁平化或映射 for 循环的输出都无法让我摆脱困境。

这也可能与我的案例陈述有关,而不是处理 None 案例,但我不确定如何处理其他案例(我知道这样说是不对的,但我的数据中不会有任何其他案例- 虽然这是动态类型语言谈话的陶醉)

data有没有办法在从到时保持预期的类型,dataExpanded同时避免不必要的循环?

4

3 回答 3

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(_))

提供所需的输出。

于 2015-01-13T19:16:01.413 回答
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))
  }                                              
于 2015-01-13T19:21:57.667 回答
0

比@enzyme 答案更详细一点,但这是一种使用递归、模式匹配和用于生成List元组的 for 表达式的方法。

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)))
于 2015-01-13T19:23:49.530 回答