web-dev-qa-db-ja.com

不変のリストから1つの要素を「削除」する慣用的なScala方法とは何ですか?

リストがありますが、リストには等しいと比較される要素が含まれている場合があります。同様のリストが必要ですが、1つの要素が削除されています。したがって、(A、B、C、B、D)から、1つだけのBを「削除」して、 (A、C、B、D)。結果の要素の順序は関係ありません。

ScalaでLISPにヒントを得た方法で記述された作業コードがあります。これを行うためのより慣用的な方法はありますか?

コンテキストは、2組の標準カードが使用されているカードゲームです。そのため、重複したカードが存在する可能性がありますが、それでも1枚ずつ再生されます。

def removeOne(c: Card, left: List[Card], right: List[Card]): List[Card] = {
  if (Nil == right) {
    return left
  }
  if (c == right.head) {
    return left ::: right.tail
  }
  return removeOne(c, right.head :: left, right.tail)
}

def removeCard(c: Card, cards: List[Card]): List[Card] = {
  return removeOne(c, Nil, cards)
}
74
Gavilan Comun

上記の回答ではこの可能性を見ていません。

scala> def remove(num: Int, list: List[Int]) = list diff List(num)
remove: (num: Int,list: List[Int])List[Int]

scala> remove(2,List(1,2,3,4,5))
res2: List[Int] = List(1, 3, 4, 5)

編集:

scala> remove(2,List(2,2,2))
res0: List[Int] = List(2, 2)

魔法のように :-)。

133

filterNotメソッドを使用できます。

val data = "test"
list = List("this", "is", "a", "test")
list.filterNot(Elm => Elm == data)
32

これを試すことができます:

scala> val (left,right) = List(1,2,3,2,4).span(_ != 2)
left: List[Int] = List(1)
right: List[Int] = List(2, 3, 2, 4)

scala> left ::: right.tail                            
res7: List[Int] = List(1, 3, 2, 4)

そして方法として:

def removeInt(i: Int, li: List[Int]) = {
   val (left, right) = li.span(_ != i)
   left ::: right.drop(1)
}
15
Frank S. Thomas

残念ながら、コレクション階層はList上の-で少し混乱しました。 ArrayBufferの場合、期待どおりに機能します。

scala> collection.mutable.ArrayBuffer(1,2,3,2,4) - 2
res0: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 3, 2, 4)

しかし、悲しいことに、ListfilterNotスタイルの実装になり、したがって「間違った」ことを行いますandは非推奨の警告をスローします(十分に賢明です。実際はfilterNotingです):

scala> List(1,2,3,2,4) - 2                          
warning: there were deprecation warnings; re-run with -deprecation for details
res1: List[Int] = List(1, 3, 4)

したがって、おそらく最も簡単なことは、Listをこの権利を行うコレクションに変換し、その後再び変換することです。

import collection.mutable.ArrayBuffer._
scala> ((ArrayBuffer() ++ List(1,2,3,2,4)) - 2).toList
res2: List[Int] = List(1, 3, 2, 4)

または、取得したコードのロジックを保持しながら、スタイルをより慣用的にすることもできます。

def removeInt(i: Int, li: List[Int]) = {
  def removeOne(i: Int, left: List[Int], right: List[Int]): List[Int] = right match {
    case r :: rest =>
      if (r == i) left.reverse ::: rest
      else removeOne(i, r :: left, rest)
    case Nil => left.reverse
  }
  removeOne(i, Nil, li)
}

scala> removeInt(2, List(1,2,3,2,4))
res3: List[Int] = List(1, 3, 2, 4)
8
Rex Kerr
 def removeAtIdx[T](idx: Int, listToRemoveFrom: List[T]): List[T] = {
    assert(listToRemoveFrom.length > idx && idx >= 0)
    val (left, _ :: right) = listToRemoveFrom.splitAt(idx)
    left ++ right
 }
4
// throws a MatchError exception if i isn't found in li
def remove[A](i:A, li:List[A]) = {
   val (head,_::tail) = li.span(i != _)
   head ::: tail
}
2
Ken Bloom

可能な解決策の1つとして、最初の適切な要素のインデックスを見つけてから、このインデックスの要素を削除できます。

def removeOne(l: List[Card], c: Card) = l indexOf c match {
    case -1 => l
    case n => (l take n) ++ (l drop (n + 1))
}
1
tenshi

どう?

def removeCard(c: Card, cards: List[Card]) = {
  val (head, tail) = cards span {c!=}   
  head ::: 
  (tail match {
    case x :: xs => xs
    case Nil => Nil
  })
}

returnが表示される場合は、何か問題があります。

1
Eugene Yokota

フォールドを使用してこれを行う方法に関する別の考え:

def remove[A](item : A, lst : List[A]) : List[A] = {
    lst.:\[List[A]](Nil)((lst, lstItem) => 
       if (lstItem == item) lst else lstItem::lst )
}
0
gdiz

一般的なテール再帰ソリューション:

def removeElement[T](list: List[T], ele: T): List[T] = {
    @tailrec
    def removeElementHelper(list: List[T],
                            accumList: List[T] = List[T]()): List[T] = {
      if (list.length == 1) {
        if (list.head == ele) accumList.reverse
        else accumList.reverse ::: list
      } else {
        list match {
          case head :: tail if (head != ele) =>
            removeElementHelper(tail, head :: accumList)
          case head :: tail if (head == ele) => (accumList.reverse ::: tail)
          case _                             => accumList
        }
      }
    }
    removeElementHelper(list)
  }
0
Shankar Shastri