Scala List 函数用于对连续的相同元素进行分组

发布于 2024-10-13 10:03:30 字数 230 浏览 3 评论 0原文

例如:

List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)

我想:

List(List(5), List(2), List(3, 3, 3), List(5, 5), List(3, 3), List(2, 2, 2))

我假设有一个简单的列表函数可以做到这一点,但我无法找到它。

Given e.g.:

List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)

I'd like to get to:

List(List(5), List(2), List(3, 3, 3), List(5, 5), List(3, 3), List(2, 2, 2))

I would assume there is a simple List function that does this, but am unable to find it.

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

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

发布评论

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

评论(8

﹏雨一样淡蓝的深情 2024-10-20 10:03:30

这是我通常使用的技巧:

def split[T](list: List[T]) : List[List[T]] = list match {
  case Nil => Nil
  case h::t => val segment = list takeWhile {h ==}
    segment :: split(list drop segment.length)
}

实际上......事实并非如此,我通常对集合类型进行抽象并使用尾递归进行优化,但希望保持答案简单。

This is the trick that I normally use:

def split[T](list: List[T]) : List[List[T]] = list match {
  case Nil => Nil
  case h::t => val segment = list takeWhile {h ==}
    segment :: split(list drop segment.length)
}

Actually... It's not, I usually abstract over the collection type and optimize with tail recursion as well, but wanted to keep the answer simple.

静赏你的温柔 2024-10-20 10:03:30
val xs = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)

这是另一种方法。

(List(xs.take(1)) /: xs.tail)((l,r) =>
  if (l.head.head==r) (r :: l.head) :: l.tail else List(r) :: l
).reverseMap(_.reverse)
val xs = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)

Here's another way.

(List(xs.take(1)) /: xs.tail)((l,r) =>
  if (l.head.head==r) (r :: l.head) :: l.tail else List(r) :: l
).reverseMap(_.reverse)
誰認得朕 2024-10-20 10:03:30

该死的雷克斯克尔,写出了我想要的答案。由于存在细微的风格差异,因此我的看法是:

list.tail.foldLeft(List(list take 1)) { 
    case (acc @ (lst @ hd :: _) :: tl, el) => 
        if (el == hd) (el :: lst) :: tl 
        else (el :: Nil) :: acc 
}

由于元素相同,因此我没有费心反转子列表。

Damn Rex Kerr, for writing the answer I'd go for. Since there are minor stylistic differences, here's my take:

list.tail.foldLeft(List(list take 1)) { 
    case (acc @ (lst @ hd :: _) :: tl, el) => 
        if (el == hd) (el :: lst) :: tl 
        else (el :: Nil) :: acc 
}

Since the elements are identical, I didn't bother reversing the sublists.

耳钉梦 2024-10-20 10:03:30
list.foldRight(List[List[Int]]()){
  (e, l) => l match {
    case (`e` :: xs) :: fs => (e :: e :: xs) :: fs
    case _ => List(e) :: l
  }
}

list.zip(false :: list.sliding(2).collect{case List(a,b) => a == b}.toList)
 .foldLeft(List[List[Int]]())((l,e) => if(e._2) (e._1 :: l.head) :: l.tail 
                                       else List(e._1) :: l ).reverse

[编辑]

//find the hidden way 
//the beauty must be somewhere
//when we talk scala

def split(l: List[Int]): List[List[Int]] = 
  l.headOption.map{x => val (h,t)=l.span{x==}; h::split(t)}.getOrElse(Nil)
list.foldRight(List[List[Int]]()){
  (e, l) => l match {
    case (`e` :: xs) :: fs => (e :: e :: xs) :: fs
    case _ => List(e) :: l
  }
}

Or

list.zip(false :: list.sliding(2).collect{case List(a,b) => a == b}.toList)
 .foldLeft(List[List[Int]]())((l,e) => if(e._2) (e._1 :: l.head) :: l.tail 
                                       else List(e._1) :: l ).reverse

[Edit]

//find the hidden way 
//the beauty must be somewhere
//when we talk scala

def split(l: List[Int]): List[List[Int]] = 
  l.headOption.map{x => val (h,t)=l.span{x==}; h::split(t)}.getOrElse(Nil)
提赋 2024-10-20 10:03:30

我在处理集合方法时拥有这些实现。最后,我检查了 inits 和 tails 的更简单实现,并忽略了 cluster。每一种新方法,无论多么简单,最终都会征收巨额税收,而这从外部很难看到。但这是我没有使用的实现。

import generic._
import scala.reflect.ClassManifest
import mutable.ListBuffer
import annotation.tailrec
import annotation.unchecked.{ uncheckedVariance => uV }

def inits: List[Repr] = repSequence(x => (x, x.init), Nil)
def tails: List[Repr] = repSequence(x => (x, x.tail), Nil)
def cluster[A1 >: A : Equiv]: List[Repr] =
  repSequence(x => x.span(y => implicitly[Equiv[A1]].equiv(y, x.head)))

private def repSequence(
  f: Traversable[A @uV] => (Traversable[A @uV], Traversable[A @uV]),
  extras: Traversable[A @uV]*): List[Repr] = {

  def mkRepr(xs: Traversable[A @uV]): Repr = newBuilder ++= xs result
  val bb = new ListBuffer[Repr]

  @tailrec def loop(xs: Repr): List[Repr] = {
    val seq = toCollection(xs)
    if (seq.isEmpty)
      return (bb ++= (extras map mkRepr)).result

    val (hd, tl) = f(seq)
    bb += mkRepr(hd)
    loop(mkRepr(tl))
  }

  loop(self.repr)
}

[编辑:我忘记了其他人不会知道内部结构。该代码是从 TraversableLike 内部编写的,因此它不会开箱即用。]

I have these implementations lying around from working on collections methods. In the end I checked in simpler implementations of inits and tails and left out cluster. Every new method no matter how simple ends up collecting a big tax which is hard to see from the outside. But here's the implementation I didn't use.

import generic._
import scala.reflect.ClassManifest
import mutable.ListBuffer
import annotation.tailrec
import annotation.unchecked.{ uncheckedVariance => uV }

def inits: List[Repr] = repSequence(x => (x, x.init), Nil)
def tails: List[Repr] = repSequence(x => (x, x.tail), Nil)
def cluster[A1 >: A : Equiv]: List[Repr] =
  repSequence(x => x.span(y => implicitly[Equiv[A1]].equiv(y, x.head)))

private def repSequence(
  f: Traversable[A @uV] => (Traversable[A @uV], Traversable[A @uV]),
  extras: Traversable[A @uV]*): List[Repr] = {

  def mkRepr(xs: Traversable[A @uV]): Repr = newBuilder ++= xs result
  val bb = new ListBuffer[Repr]

  @tailrec def loop(xs: Repr): List[Repr] = {
    val seq = toCollection(xs)
    if (seq.isEmpty)
      return (bb ++= (extras map mkRepr)).result

    val (hd, tl) = f(seq)
    bb += mkRepr(hd)
    loop(mkRepr(tl))
  }

  loop(self.repr)
}

[Edit: I forget other people won't know the internals. This code is written from inside of TraversableLike, so it wouldn't run out of the box.]

一百个冬季 2024-10-20 10:03:30

这是一个稍微干净一点的版本:

def groupConsequtive[A](list: List[A]): List[List[A]] = list match {
  case head :: tail =>
    val (t1, t2) = tail.span(_ == head)
    (head :: t1) :: groupConsequtive(t2)
  case _ => Nil  
}

尾递归版本

@tailrec
def groupConsequtive[A](list: List[A], acc: List[List[A]] = Nil): List[List[A]] = list match {
  case head :: tail =>
    val (t1, t2) = tail.span(_ == head)
    groupConsequtive(t2, acc :+ (head :: t1))
  case _ => acc
}

Here's a slightly cleaner one:

def groupConsequtive[A](list: List[A]): List[List[A]] = list match {
  case head :: tail =>
    val (t1, t2) = tail.span(_ == head)
    (head :: t1) :: groupConsequtive(t2)
  case _ => Nil  
}

tail-recursive version

@tailrec
def groupConsequtive[A](list: List[A], acc: List[List[A]] = Nil): List[List[A]] = list match {
  case head :: tail =>
    val (t1, t2) = tail.span(_ == head)
    groupConsequtive(t2, acc :+ (head :: t1))
  case _ => acc
}
阿楠 2024-10-20 10:03:30

这是受 @Kevin Wright 和 @Landei 启发的尾递归解决方案:

@tailrec
def sliceEqual[A](s: Seq[A], acc: Seq[Seq[A]] = Seq()): Seq[Seq[A]] = {
  s match {
    case fst :: rest =>
      val (l, r) = s.span(fst==)
      sliceEqual(r, acc :+ l)
    case Nil => acc
  }
}

Here's a tail-recursive solution inspired by @Kevin Wright and @Landei:

@tailrec
def sliceEqual[A](s: Seq[A], acc: Seq[Seq[A]] = Seq()): Seq[Seq[A]] = {
  s match {
    case fst :: rest =>
      val (l, r) = s.span(fst==)
      sliceEqual(r, acc :+ l)
    case Nil => acc
  }
}
浪漫之都 2024-10-20 10:03:30

这可能更简单:

val input = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
input groupBy identity values

this could be simpler:

val input = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
input groupBy identity values
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文