Scala - 在保持相同类型的同时扩展各种类型的列表
Scala - expand a list of various types while keeping the same types
我有一个包含各种类型的列表,如下所示:
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)——因此理想情况下它看起来像(强调每次迭代都需要将 Int 从 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)))
结果看起来是在正确的路径上,但是展开的元素嵌套在它们自己的列表中,因此我认为 Type 是错误的。没有多少 flatMapping 或扁平化或映射 for 循环的输出让我摆脱困境。
这可能也与我的案例陈述有关,没有处理 None 个案例,但我不确定如何处理其他案例(我知道这样说不对,但我不会'我的数据中真的没有任何其他情况 - 尽管这是动态类型语言的醉人谈话)
有没有办法在从 data
到 dataExpanded
时保持预期的类型,同时避免不必要的循环?
考虑元组的大小写 类,像这样
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(_))
提供所需的输出。
你很接近,你可以做到
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))
}
比@enzyme 的回答稍微冗长一点,但这里有一种使用递归、模式匹配和 for 表达式生成元组 List
的方法。
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)))
我有一个包含各种类型的列表,如下所示:
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)——因此理想情况下它看起来像(强调每次迭代都需要将 Int 从 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)))
结果看起来是在正确的路径上,但是展开的元素嵌套在它们自己的列表中,因此我认为 Type 是错误的。没有多少 flatMapping 或扁平化或映射 for 循环的输出让我摆脱困境。
这可能也与我的案例陈述有关,没有处理 None 个案例,但我不确定如何处理其他案例(我知道这样说不对,但我不会'我的数据中真的没有任何其他情况 - 尽管这是动态类型语言的醉人谈话)
有没有办法在从 data
到 dataExpanded
时保持预期的类型,同时避免不必要的循环?
考虑元组的大小写 类,像这样
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(_))
提供所需的输出。
你很接近,你可以做到
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))
}
比@enzyme 的回答稍微冗长一点,但这里有一种使用递归、模式匹配和 for 表达式生成元组 List
的方法。
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)))