Scala 中有没有办法将 Seq[(String, String)] 转换为 Seq[String]?
Posted
技术标签:
【中文标题】Scala 中有没有办法将 Seq[(String, String)] 转换为 Seq[String]?【英文标题】:Is there a way in Scala to convert Seq[(String, String)] To Seq[String]? 【发布时间】:2019-10-13 11:17:48 【问题描述】:我是 Scala 的新手,并且一般都在编码,如果这个问题有点基本但希望得到帮助,很抱歉!
我目前有一个产生Seq[(String, String)]
的函数,然后我想将其转换为Seq[String]
。
根据函数的迭代,向量的维度会有所不同,因此一些结果是Seq[(String, String)]
,其他是Seq[(String, String, String)]
等等。所以理想情况下,我可以对每个输出使用相同的函数。
我尝试过使用.flatten
和split[","]
,但不确定我还可以使用哪些其他方法。
对于一个样本值,函数的输出如下所示:
res17: Seq[(String, String)] = Vector((u, v),(w, x))
理想的结果是Vector(u,v,w,x)
【问题讨论】:
首先要了解为什么需要这样做。你能展示生成这些不同类型的函数吗? 对于字符串,可能使用某种concat函数? 你确定你有元组吗?还是它们是内部向量?其次,您只想展平内部元组/集合并保留所有未修改的项目,还是您想做其他事情?您不清楚您的问题、样本数据或预期输出。 您只需要.flatMapcase (a,b) => Vector(a,b)
。根据需要添加/调整 case
以获得所需的元组长度。
感谢您的回复 - 使用 .flatMapcase (a,b) => Vector(a,b) 非常适合每种情况,谢谢 jwvh!
【参考方案1】:
考虑以类型安全的方式提供abstracting over arity 方式的无形方法:
import shapeless._
import shapeless.ops.hlist
import syntax.std.tuple._
def flattenTupleN[P <: Product, L <: HList](
ps: List[P]
)(implicit gen: Generic.Aux[P, L],
toT: hlist.ToTraversable.Aux[L, List, String]
): List[String] =
ps.flatMap(p => gen.to(p).toList)
val t1: List[(String, String)] = List(("u", "v"), ("w", "x"))
val t2: List[(String, String, String)] = List(("a", "b", "c"), ("d", "e", "f"))
val t3: List[(Int, Double, String)] = List((42, 3.14, "Picard"))
flattenTupleN(t1)
flattenTupleN(t2)
// flattenTupleN(t3) // compile-time error
哪个输出
res0: List[String] = List(u, v, w, x)
res1: List[String] = List(a, b, c, d, e, f)
这是一种不安全但开箱即用的方法:
def flattenTupleNUnsafe(ps: List[Product]): List[String] =
ps.flatMap(_.productIterator.map(_.toString))
flattenTupleNUnsafe(t1)
flattenTupleNUnsafe(t2)
flattenTupleNUnsafe(t3) // compiles OK but is a bad idea!
哪个输出
res2: List[String] = List(u, v, w, x)
res3: List[String] = List(a, b, c, d, e, f)
res4: List[String] = List(42, 3.14, Picard)
注意由于类型安全的丢失 flattenTupleNUnsafe(t3)
编译得很好并在程序中引入了逻辑错误。
【讨论】:
【参考方案2】:我同意那些询问有关您的用例的更多信息的人的观点。如果不了解您尝试转换的数据的更多信息,就很难推荐一个简洁的解决方案来满足您的需求。
请暂时考虑一下我要说的话,因为我对您要做什么还不够了解。
你说你输出的元组可以变化。您是否考虑过将所有内容从 Tuple 转换为 Vector?
所以不是
res17: Vector[(String, String)] = Vector((u, v),(w, x))
使用
res17: Vector[Vector[String]] = Vector(Vector(u, v),Vector(w, x))
然后,您可以通过调用 flatMap 或 flatten 轻松地将 Vector 的 Vector 转换为单个 Vector,根据您的问题,听起来您已经知道该怎么做。
我从阅读您的问题中得到的另一个印象是,如果您想保留一个固定长度的参数列表,并从该参数列表转换为 Vector,您可能需要查看案例类而不是 Tuple。
因此,不要定义Tuple2
或Tuple3
,而是定义一个允许编译器对您的程序进行类型检查的继承层次结构。
类似这样的:
trait MyData
case class 2MemberData(data1: String, data2: String) extends MyData
case class 3MemberData(data1: String, data2: String, data3: String) extends MyData
case class 4MemberData(data1: String, data2: String, data3: String, data4: String) extends My Data
这样,您的函数可以输出 Vector[MyData] 类型的值,然后您可以使用模式匹配将其展平。所以像
def processData: Vector[MyData]
def cleanUp(input: Vector[MyData]): Vector[String]
其中 cleanUp 的实现方式如下:
def cleanUp(input: Vector[MyData]): Vector[String] =
input.flatMap d =>
d match
case 2MemberData(data1, data2) => Vector(data1, data2)
case 3MemberData(data1, data2, data3) => Vector(data1, data2, data3)
case 4MemberData(data1, data2, data3, data4) => Vector(data1, data2, data3, data4)
我只是把想法扔在那里,不知道我所说的是否有帮助。这实际上取决于周围的代码是什么样的。如果您有任何问题,请随时提出。
【讨论】:
以上是关于Scala 中有没有办法将 Seq[(String, String)] 转换为 Seq[String]?的主要内容,如果未能解决你的问题,请参考以下文章
在 Java 代码中从 scala.collection.Seq<String> 转换为 java.util.List<String>