Какой хороший и функциональный способ поменять элементы коллекции в Scala?

string s = "ABCDEFGH";
s= s.Remove(3, 2).Insert(3, "ZX");
14
задан Eugene Yokota 15 December 2010 в 20:39
поделиться

4 ответа

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

def swapWithNext[T](l: List[T], e : T) : List[T] = l match {
  case Nil => Nil
  case `e`::next::tl => next::e::tl
  case hd::tl => hd::swapWithNext(tl, e)
}
10
ответ дан 1 December 2019 в 12:12
поделиться

Альтернативная реализация метода венечки:

def swapWithNext[T](l: List[T], e: T): List[T] = {
  val (h,t) = l.span(_ != e)
  h ::: t.tail.head :: e :: t.tail.tail
}

Обратите внимание, что это не срабатывает с ошибкой, если e - последний элемент.

Если вы знаете оба элемента, и каждый элемент встречается только один раз, он становится более элегантным:

def swap[T](l: List[T], a:T, b:T) : List[T] = l.map(_ match {
  case `a` => b
  case `b` => a
  case e => e }
)
1
ответ дан 1 December 2019 в 12:12
поделиться

Застежка-молния - это чисто функциональная структура данных с указателем на эту структуру. Другими словами, это элемент с контекстом в некоторой структуре.

Например, библиотека Scalaz предоставляет класс Zipper , который моделирует список с определенным элементом списка в фокусе.

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

import scalaz._
import Scalaz._

val z: Option[Zipper[Int]] = List(1,2,3,4).toZipper

Вы можете переместить фокус молнии, используя методы на Застежка-молния , например, вы можете перейти к следующему смещению от текущего фокуса.

val z2: Option[Zipper[Int]] = z >>= (_.next)

Это похоже на List.tail , за исключением того, что он запоминает, где был.

Затем, когда выбранный вами элемент окажется в фокусе, вы можете изменить элементы вокруг фокуса.

val swappedWithNext: Option[Zipper[Int]] =
  for (x <- z2;
       y <- x.delete)
    yield y.insertLeft(x.focus)

Примечание: это последняя версия заголовка ствола Scalaz, в которой исправлена ​​ошибка хвостовой рекурсии find и move Зиппера.

Тогда вам нужен простой метод:

def swapWithNext[T](l: List[T], p: T => Boolean) : List[T] = (for {
  z <- l.toZipper
  y <- z.findZ(p)
  x <- y.delete
} yield x.insertLeft(y.focus).toStream.toList) getOrElse l

Соответствует элементу, основанному на предикате p . Но вы можете пойти дальше и рассмотреть все близлежащие элементы. Например, чтобы реализовать сортировку вставкой.

8
ответ дан 1 December 2019 в 12:12
поделиться

Общая версия Landei:

import scala.collection.generic.CanBuildFrom
import scala.collection.SeqLike
def swapWithNext[A,CC](cc: CC, e: A)(implicit w1: CC => SeqLike[A,CC],
                                        w2: CanBuildFrom[CC,A,CC]): CC = {
    val seq: SeqLike[A,CC] = cc
    val (h,t) = seq.span(_ != e)
    val (m,l) = (t.head,t.tail)
    if(l.isEmpty) cc
    else (h :+ l.head :+ m) ++ l.tail
}

некоторые виды использования :

scala> swapWithNext(List(1,2,3,4),3)
res0: List[Int] = List(1, 2, 4, 3)

scala> swapWithNext("abcdef",'d')
res2: java.lang.String = abcedf

scala> swapWithNext(Array(1,2,3,4,5),2)
res3: Array[Int] = Array(1, 3, 2, 4, 5)

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

scala>
5
ответ дан 1 December 2019 в 12:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: