Generics 以通用方式对Scala集合进行操作

Generics 以通用方式对Scala集合进行操作,generics,scala,types,scala-collections,generic-programming,Generics,Scala,Types,Scala Collections,Generic Programming,我编写了查找函数(LCS)。例如,对于chars BANANA和ATANA的两个序列,它返回AANA。实现是对递归算法的幼稚、低效的适应,但它和这个问题的目的无关 def LCS[T](a: Seq[T], b: Seq[T]): Seq[T] = { if (a.isEmpty || b.isEmpty) Seq.empty else if (a.head == b.head) a.head +: LCS(a.tail, b.tail) else

我编写了查找函数(LCS)。例如,对于chars BANANA和ATANA的两个序列,它返回AANA。实现是对递归算法的幼稚、低效的适应,但它和这个问题的目的无关

def LCS[T](a: Seq[T], b: Seq[T]): Seq[T] = {
    if (a.isEmpty || b.isEmpty)
      Seq.empty
    else if (a.head == b.head)
      a.head +: LCS(a.tail, b.tail)
    else {
      val case1 = LCS(a.tail, b)
      val case2 = LCS(a, b.tail)
      if (case1.length > case2.length) case1 else case2
    }
}
我想以最通用的方式重构这个函数。当前的实现适用于任何类型的输入序列,但总是返回List[T]类型的集合。我希望实现以下行为:

LCS(List('B','A','N','A','N','A'), List('A','T','A','N','A')) -> List('A','A','N','A') LCS(Vector('B','A','N','A','N','A'), Vector('A','T','A','N','A')) -> Vector('A','A','N','A') ...and so on for all other Seqs... LCS(列表('B','A','N','A','N','A'),列表('A','T','A','N','A'))->列表('A','A','N','A')) LCS(向量('B','A','N','A','N','A'),向量('A','T','A','N','A'))->向量('A','A','N','A')) …以此类推所有其他序列。。。 如果LCS也能处理字符串和数组,那就太好了:

LCS(“香蕉”、“阿塔纳”)->“阿塔纳” LCS(数组('B','A','N','A','N','A'),数组('A','T','A','N','A'))->数组('A','A','N','A')) 我相信在Scala2.8通用集合库的帮助下,至少可以实现第一个需求。会很高兴看到“重型”机器,如更高级的多态性、类型类、CanBuildFrom等等


谢谢

Seq.empty
替换为
a.companion.empty
为我提供了一个具有以下行为的函数:

scala> LCS(Vector(1, 2, 1, 2, 3), Vector(1, 1, 3))
res3: Seq[Int] = Vector(1, 1, 3)

scala> LCS(List(1, 2, 1, 2, 3), List(1, 1, 3))
res4: Seq[Int] = List(1, 1, 3)

scala> LCS("BANANA", "ANA")                       
res5: Seq[Char] = Vector(A, N, A)

scala> LCS(Array(1, 2, 1, 2, 3), Array(1, 1, 3))
res6: Seq[Int] = ArrayBuffer(1, 1, 3)

为了澄清我的评论,以下是您将要做的(没有给出解释——关于这一点,请参阅的答案)


可以直接在内部函数中使用生成器,但必须重新编写算法;实际上,您将项目添加到列表的开头,而构建器将项目添加到列表的结尾。因此,为了保持相同的算法,我们制作了一个中间列表。

虽然这并不完全符合目标,但您应该能够通过遵循问题的答案来完成您想要的任务。但是,我建议您不要使用直接的递归,因为这样做需要大量的构建器。一个与构建器一起递归的帮助函数就可以完成这个任务。谢谢Rex!你“拉皮条”scala系列的精彩表演正是我想知道的。必须向所有有兴趣将自己在集合上操作的泛型方法与scala集合框架集成的人阅读。这只是部分解决方案。如您所见,在每种情况下,编译时类型都是Seq[T]。此外,它不能以正确的方式处理字符串和数组。见上面雷克斯·克尔的答案,他完全解决了这个问题。
scala> LCS(Vector(1, 2, 1, 2, 3), Vector(1, 1, 3))
res3: Seq[Int] = Vector(1, 1, 3)

scala> LCS(List(1, 2, 1, 2, 3), List(1, 1, 3))
res4: Seq[Int] = List(1, 1, 3)

scala> LCS("BANANA", "ANA")                       
res5: Seq[Char] = Vector(A, N, A)

scala> LCS(Array(1, 2, 1, 2, 3), Array(1, 1, 3))
res6: Seq[Int] = ArrayBuffer(1, 1, 3)
def LCS[A,C](a: C, b: C)(
  implicit c2i: C => Iterable[A], cbf: collection.generic.CanBuildFrom[C,A,C]
): C = {
  val builder = cbf()
  def ListLCS(a: Iterable[A], b: Iterable[A]): List[A] = {
    if (a.isEmpty || b.isEmpty) Nil
    else if (a.head==b.head) a.head :: ListLCS(a.tail,b)
    else {
      val case1 = ListLCS(a.tail, b)
      val case2 = ListLCS(a, b.tail)
      if (case1.length > case2.length) case1 else case2
    }
  }
  builder ++= ListLCS( c2i(a), c2i(b) )
  builder.result()
}