list - 如何扩展 Scala 列表以启用不是按显式位置而是按给定谓词/条件的切片

标签 list scala collections slice

为了

trait Item
case class TypeA(i: Int) extends Item
case class TypeB(i: Int) extends Item

考虑一个 Scala 列表,例如

val myList = List(TypeA(1), TypeB(11), TypeB(12), 
                  TypeA(2), TypeB(21), 
                  TypeA(3), TypeB(31))

目标是定义一个新的 slice 方法,该方法可以应用于 myList 并以谓词或条件作为参数;例如

myList.slice { x => x.isInstanceOf[TypeA] }

会交付

List(List(TypeA(1), TypeB(11), TypeB(12)), 
     List(TypeA(2), TypeB(21)), 
     List(TypeA(3), TypeB(31)))

在这个例子中,相同的结果将通过

实现
myList.slice { case TypeA(x) => x < 10 }

非常感谢。

最佳答案

List 已经有一个 slice 方法 - 它采用开始索引和结束索引之间的元素子集。您正在寻找的是 span 方法的重复应用:

def span(p: (A) ⇒ Boolean): (List[A], List[A])

记录为:

Splits this list into a prefix/suffix pair according to a predicate.

Note: c span p is equivalent to (but possibly more efficient than) (c takeWhile p, c dropWhile p), provided the evaluation of the predicate p does not cause any side-effects.

returns: a pair consisting of the longest prefix of this list whose elements all satisfy p, and the rest of this list.

您可以通过将此方法与反向谓词重复使用来获得所需的内容,并使用额外的逻辑来确保返回的列表都不为空。

import annotation.tailrec

def multiSpan[A](xs: List[A])(splitOn: (A) => Boolean): List[List[A]] = {
  @tailrec
  def loop(xs: List[A], acc: List[List[A]]) : List[List[A]] = xs match {
    case Nil => acc

    case x :: Nil => List(x) :: acc

    case h :: t =>
      val (pre,post) = t.span(!splitOn(_))
      loop(post, (h :: pre) :: acc)
  }
  loop(xs, Nil).reverse
}

更新

根据原始帖子评论中的要求,这里有一个丰富列表而不是独立方法的版本:

implicit class AddMultispanToList[A](val list: List[A]) extends AnyVal {
  def multiSpan(splitOn: (A) => Boolean): List[List[A]] = {
    @tailrec
    def loop(xs: List[A], acc: List[List[A]]) : List[List[A]] = xs match {
      case Nil => acc

      case x :: Nil => List(x) :: acc

      case h :: t =>
        val (pre,post) = t.span(!splitOn(_))
        loop(post, (h :: pre) :: acc)
    }
    loop(list, Nil).reverse
  }
}

用作:

myList.multiSpan(_.isInstanceOf[TypeA])

关于list - 如何扩展 Scala 列表以启用不是按显式位置而是按给定谓词/条件的切片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21800041/

相关文章:

java - Java 的前缀匹配/trie?

list - Haskell ~ last 是否遍历整个列表?

list - 如何在 Haskell 中正确使用守卫?

java - 如何将 List<List<String>> 转换为 Object[][]

python - 在 Pwm 中将字符串输出为列表

macos - -bash:scala:找不到命令

scala - 在 Scala 中,我可以覆盖包含列表的具体字段并在子类中向其附加某些内容吗?

java - Collections.copy(dest, src) 仍然引用源集合

scala - 理解 Scala 中的类型推断

java - 根据相似索引收集列表集合