Nano Hash - криптовалюты, майнинг, программирование

Функция Scala List для группировки последовательных одинаковых элементов

Учитывая, например:

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))

Я бы предположил, что есть простая функция List, которая делает это, но я не могу ее найти.

21.01.2011

Ответы:


1

Это трюк, который я обычно использую:

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)
}

На самом деле... Это не так, я обычно абстрагируюсь от типа коллекции и также оптимизирую с помощью хвостовой рекурсии, но хотел, чтобы ответ был простым.

21.01.2011
  • Хороший. Но не будет ли это достаточно распространенным явлением, чтобы оправдать собственную библиотечную функцию? 21.01.2011
  • @KevinWright также оптимизируйте с помощью хвостовой рекурсии -› Как бы вы это сделали? 29.02.2016
  • Неважно - я только что узнал о tailrec. Кроме того, как это сделать с ленивой оценкой, если у вас есть Iterable вместо списка? 29.02.2016
  • @vishvAs vAsuki: опубликовал решение tailrec ниже 23.06.2016
  • Не могли бы вы объяснить свое решение? В частности, откуда взялось t? 18.03.2019

  • 2
    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)
    
    21.01.2011

    3

    Проклятый Рекс Керр, за то, что написал ответ, на который я бы пошел. Поскольку есть небольшие стилистические различия, вот мое мнение:

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

    Поскольку элементы идентичны, я не стал менять местами подсписки.

    21.01.2011
  • Не могли бы вы объяснить (или указать мне ссылку) case (acc @ (lst @ hd:: _). Я никогда раньше не видел такого синтаксиса. Заранее спасибо. 12.03.2015
  • @gashu При сопоставлении с образцом x @ y означает, что x будет назначено все, что сопоставляется с помощью y. Так, например, x @ _ :: _ присвоит x непустой список (то есть список с головой и хвостом, соответствующий _ :: _). Таким образом, acc вверху — это весь список, а lst — его начало. 12.03.2015
  • @ daniel-c-sobral, значит, такие выражения используются только при сопоставлении с образцом или в другом контексте они означают что-то другое? 12.03.2015
  • @gashu @ также используется для аннотаций, почти так же, как Java. Это совсем не похоже на приведенное выше, но это также использование знака at. 12.03.2015

  • 4
    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
    

    [Изменить]

    //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)
    
    21.01.2011
  • Будет ли какой-либо из подходов работать со значениями NaN? Я пытаюсь выяснить, вижу ли я n последовательных значений Double.NaN в векторе. Глядя на решения, размещенные здесь, кажется, что я ничего не придумаю сам. 19.05.2016
  • Значения NaN действительно потребуют специальной обработки. Может быть, вы могли бы обернуть Ints в Option[Int] и преобразовать NaNs в Nones. Тогда обычные решения, основанные на равенстве, будут работать. Или вы можете написать свою собственную функцию равенства. 22.05.2016

  • 5

    У меня есть эти реализации, лежащие вокруг работы над методами коллекций. В конце концов я проверил более простые реализации инициализации и хвостов и исключил кластер. Каждый новый метод, каким бы простым он ни был, заканчивается сбором большого налога, который трудно увидеть со стороны. Но вот реализация, которую я не использовал.

    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, так что он не будет запускаться из коробки.]

    22.01.2011

    6

    Вот решение с хвостовой рекурсией, вдохновленное @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
      }
    }
    
    23.06.2016

    7

    Вот немного чище:

    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
    }
    
    19.06.2019
  • Насколько я понимаю, недостатком решения с хвостовой рекурсией здесь является то, что операция prepend менее эффективна по времени, не так ли? 30.11.2020

  • 8

    это может быть проще:

    val input = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
    input groupBy identity values
    
    24.01.2011
  • Это сгруппирует все одинаковые элементы, а не только последовательные. 24.01.2011
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..