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

В моем проекте один общий прецедент продолжается. В какой-то момент у меня есть отсортированная коллекция какого-то рода (List, Seq и т.д.) Не имеет значения) и один элемент этой коллекции. То, что я хочу сделать, - это заменить данный элемент следующим элементом (если этот элемент существует) или в некоторый момент с предыдущим элементом.

Я хорошо осведомлен о способах достижения этой цели с использованием процедурных методов программирования. Мой вопрос в том, что было бы хорошим способом решить проблему с помощью функционального программирования (в Scala)?


Спасибо всем за ваши ответы. Я принял тот, который я сам все понял. Поскольку я не функциональный программист (пока), мне трудно решить, какой ответ был действительно лучшим. На мой взгляд, все они довольно хороши.

Ответы

Ответ 1

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

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

Ответ 2

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

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

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

import scalaz._
import Scalaz._

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

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

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 с помощью Zipper.

В этом случае вам нужен именно тот метод:

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. Но вы можете пойти дальше и рассмотреть все близлежащие элементы. Например, для реализации сортировки вставки.

Ответ 3

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

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>

Ответ 4

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

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

Ответ 5

Как насчет:

  val identifierPosition = 3;
  val l = "this is a identifierhere here";
  val sl = l.split(" ").toList;

  val elementAtPos = sl(identifierPosition)
  val swapped = elementAtPos :: dropIndex(sl , identifierPosition)

  println(swapped)

  def dropIndex[T](xs: List[T], n: Int) : List[T] = {
    val (l1, l2) = xs splitAt n
    l1 ::: (l2 drop 1)
  }

kudos http://www.scala-lang.org/old/node/5286 для функции dropIndex