Какой хороший и функциональный способ обмена элементами коллекции в 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