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)] 等等。所以理想情况下,我可以对每个输出使用相同的函数。

我尝试过使用.flattensplit[","],但不确定我还可以使用哪些其他方法。

对于一个样本值,函数的输出如下所示:

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。

因此,不要定义Tuple2Tuple3,而是定义一个允许编译器对您的程序进行类型检查的继承层次结构。

类似这样的:

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]?的主要内容,如果未能解决你的问题,请参考以下文章

在Scala中对列表/序列进行模式匹配时解决类型擦除问题

在 Java 代码中从 scala.collection.Seq<String> 转换为 java.util.List<String>

使用 FoldLeft 在 Scala 中制作邻接表

Scala Spark用NULL替换空String

Java 的 List 与 Scala 的 Seq 相互转换

akka HttpResponse 将正文读取为 String scala