14

私のプロジェクトでは、1つの一般的なユースケースが出続けています。ある時点で、ある種のソートされたコレクション(List、Seqなどは関係ありません)とこのコレクションの1つの要素があります。私がやりたいのは、指定された要素を次の要素(この要素が存在する場合)と交換するか、場合によっては前の要素と交換することです。

私は、手続き型プログラミング手法を使用してこれを実現する方法をよく知っています。私の質問は、関数型プログラミング(Scala)を使用して問題を解決するための良い方法は何でしょうか?


回答ありがとうございます。私自身が最も理解しているものを受け入れました。私は(まだ)関数型プログラマーではないので、どちらの答えが本当に最良であるかを判断するのはちょっと難しいです。私の意見では、それらはすべてかなり良いです。

4

5 に答える 5

10

以下は、リスト内の次の要素を使用したスワップの機能バージョンです。要素をスワップした新しいリストを作成するだけです。

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)
}
于 2010-07-26T14:22:55.500 に答える
8

ジッパーは、その構造へのポインターを持つ純粋な機能データ構造です。言い換えれば、それはある構造のコンテキストを持つ要素です。

たとえば、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トランクヘッドであり、Zipperの末尾再帰findmoveメソッドのバグが修正されています。

必要な方法は次のとおりです。

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ます。しかし、さらに進んで、近くのすべての要素も考慮することができます。たとえば、挿入ソートを実装します。

于 2010-07-27T12:12:22.800 に答える
5

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>
于 2010-07-26T15:37:48.963 に答える
1

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が最後の要素である場合、これはエラーで失敗することに注意してください。

両方の要素を知っていて、すべての要素が1回だけ発生する場合は、よりエレガントになります。

def swap[T](l: List[T], a:T, b:T) : List[T] = l.map(_ match {
  case `a` => b
  case `b` => a
  case e => e }
)
于 2010-07-26T14:55:40.083 に答える
0

どうですか:

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

dropIndex関数についてはhttp://www.scala-lang.org/old/node/5286を称賛します

于 2015-08-10T22:20:22.487 に答える