如何在 Scala 中对可变长度的重复序列进行分组

发布于 2024-11-25 16:03:37 字数 985 浏览 1 评论 0原文

我有一个以某种模式重复的整数集合:

val repeatingSequence = List(1,2,3,1,2,3,4,1,2,1,2,3,4,5)

我想在模式重复时将该列表分段;在本例中,当序列返回到 1 时:

val groupedBySequence = List(List(1,2,3), List(1,2,3,4), List(1,2), List(1,2,3,4,5))

请注意,当序列跳回 1 时我正在分组,但序列可以是任意长度。我和我的同事通过添加一个名为“groupWhen”的附加方法解决了这个问题。

class IteratorW[A](itr: Iterator[A]) {
  def groupWhen(fn: A => Boolean): Iterator[Seq[A]] = {
    val bitr = itr.buffered
    new Iterator[Seq[A]] {
      override def hasNext = bitr.hasNext
      override def next = {
        val xs = collection.mutable.ListBuffer(bitr.next)
        while (bitr.hasNext && !fn(bitr.head)) xs += bitr.next
        xs.toSeq
      }
    }
  }
}
implicit def ToIteratorW[A](itr: Iterator[A]): IteratorW[A] = new IteratorW(itr)

> repeatingSequence.iterator.groupWhen(_ == 1).toSeq
List(List(1,2,3), List(1,2,3,4), List(1,2), List(1,2,3,4,5))

但是,我们都觉得集合库中潜藏着一个更优雅的解决方案。

I have a collection of ints that repeat themselves in a pattern:

val repeatingSequence = List(1,2,3,1,2,3,4,1,2,1,2,3,4,5)

I'd like to section that List up when the pattern repeats itself; in this case, when the sequence goes back to 1:

val groupedBySequence = List(List(1,2,3), List(1,2,3,4), List(1,2), List(1,2,3,4,5))

Notice that I'm grouping when the sequence jumps back to 1, but that the sequence can be of arbitrary length. My colleague and I have solved it by adding an additional method called 'groupWhen'

class IteratorW[A](itr: Iterator[A]) {
  def groupWhen(fn: A => Boolean): Iterator[Seq[A]] = {
    val bitr = itr.buffered
    new Iterator[Seq[A]] {
      override def hasNext = bitr.hasNext
      override def next = {
        val xs = collection.mutable.ListBuffer(bitr.next)
        while (bitr.hasNext && !fn(bitr.head)) xs += bitr.next
        xs.toSeq
      }
    }
  }
}
implicit def ToIteratorW[A](itr: Iterator[A]): IteratorW[A] = new IteratorW(itr)

> repeatingSequence.iterator.groupWhen(_ == 1).toSeq
List(List(1,2,3), List(1,2,3,4), List(1,2), List(1,2,3,4,5))

However, we both feel like there's a more elegant solution lurking in the collection library.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

乜一 2024-12-02 16:03:37

给定一个迭代器 itr,这就能解决问题:

val head = iter.next()
val out = (
  Iterator continually {iter takeWhile (_ != head)}
  takeWhile {!_.isEmpty}
  map {head :: _.toList}
).toList

Given an iterator itr, this will do the trick:

val head = iter.next()
val out = (
  Iterator continually {iter takeWhile (_ != head)}
  takeWhile {!_.isEmpty}
  map {head :: _.toList}
).toList
错々过的事 2024-12-02 16:03:37

众所周知,fold 可以做所有事情...;)

  val rs = List(1,2,3,1,2,3,4,1,2,1,2,3,4,5)
  val res = (rs++List(1)).foldLeft((List[List[Int]](),List[Int]()))((acc,e) => acc match {
    case (res,subl) => {
      if (e == 1) ((subl.reverse)::res,1::Nil) else (res, e::subl)
    }
  })
  println(res._1.reverse.tail)

请将此视为混淆的 Scala 竞赛的条目,而不是真正的答案。

As well all know, fold can do everything... ;)

  val rs = List(1,2,3,1,2,3,4,1,2,1,2,3,4,5)
  val res = (rs++List(1)).foldLeft((List[List[Int]](),List[Int]()))((acc,e) => acc match {
    case (res,subl) => {
      if (e == 1) ((subl.reverse)::res,1::Nil) else (res, e::subl)
    }
  })
  println(res._1.reverse.tail)

Please regard this as an entry for the obfuscated Scala contest rather than as a real answer.

陌伤ぢ 2024-12-02 16:03:37

这是我使用 span 提出的一个不太优雅的解决方案:

def groupWhen[A](fn: A => Boolean)(xs: List[A]): List[List[A]] = {
  xs.span(!fn(_)) match {
    case (Nil, Nil) => Nil
    case (Nil, z::zs) => groupWhen(fn)(zs) match {
      case ys::yss => (z::ys) :: yss
      case Nil => List(List(z))
    }
    case (ys, zs) => ys :: groupWhen(fn)(zs)
  }
}

scala> groupWhen[Int](_==1)(List(1,2,3,1,2,3,4,1,2,3,4,5))
res39: List[List[Int]] = List(List(1, 2, 3), List(1, 2, 3, 4), List(1, 2, 3, 4, 5))

scala> groupWhen[Int](_==1)(List(5,4,3,2,1,2,3,1,2,3,4,1,2,3,4,5))
res40: List[List[Int]] = List(List(5, 4, 3, 2), List(1, 2, 3), List(1, 2, 3, 4), List(1, 2, 3, 4, 5))

Here's a not-exactly-elegant solution I bashed out using span:

def groupWhen[A](fn: A => Boolean)(xs: List[A]): List[List[A]] = {
  xs.span(!fn(_)) match {
    case (Nil, Nil) => Nil
    case (Nil, z::zs) => groupWhen(fn)(zs) match {
      case ys::yss => (z::ys) :: yss
      case Nil => List(List(z))
    }
    case (ys, zs) => ys :: groupWhen(fn)(zs)
  }
}

scala> groupWhen[Int](_==1)(List(1,2,3,1,2,3,4,1,2,3,4,5))
res39: List[List[Int]] = List(List(1, 2, 3), List(1, 2, 3, 4), List(1, 2, 3, 4, 5))

scala> groupWhen[Int](_==1)(List(5,4,3,2,1,2,3,1,2,3,4,1,2,3,4,5))
res40: List[List[Int]] = List(List(5, 4, 3, 2), List(1, 2, 3), List(1, 2, 3, 4), List(1, 2, 3, 4, 5))
电影里的梦 2024-12-02 16:03:37
import scala.collection.mutable.ListBuffer
import scala.collection.breakOut

val repeatingSequence = List(1,2,3,1,2,3,4,1,2,1,2,3,4,5)
val groupedBySequence: List[List[Int]] = repeatingSequence.foldLeft(ListBuffer[ListBuffer[Int]]()) {
  case (acc, 1) => acc += ListBuffer(1)
  case (acc, n) => acc.last += n; acc
}.map(_.toList)(breakOut)
import scala.collection.mutable.ListBuffer
import scala.collection.breakOut

val repeatingSequence = List(1,2,3,1,2,3,4,1,2,1,2,3,4,5)
val groupedBySequence: List[List[Int]] = repeatingSequence.foldLeft(ListBuffer[ListBuffer[Int]]()) {
  case (acc, 1) => acc += ListBuffer(1)
  case (acc, n) => acc.last += n; acc
}.map(_.toList)(breakOut)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文