3

たとえば、特定のリストまたは配列に対して

val list = (1 to 3).toList
val array = (1 to 3).toArray

たとえば、コレクション型との間でマッピングされる特定の関数

def f(v: Int): Int = v + 10

orfの i 番目の要素に適用する方法listarray

list.myApply(f, ith = 2)
res: List(1,12,3)

そしてまた

array.myApply(f, ith = 2)
res: Array(1,12,3)
4

3 に答える 3

7

tl;dr

import scala.collection.SeqLike
import scala.collection.generic.CanBuildFrom

implicit class Seq_[A, Repr, 
    S : ({type L[X] = X => SeqLike[A, Repr]})#L](seq: S) {

  def myApply[B >: A, That](f: A => B, ith: Int)
      (implicit bf: CanBuildFrom[Repr, B, That]): That =
    seq.updated(ith - 1, f(seq(ith - 1)))
}

討論

単純な近似:

implicit class Seq_[A](seq: Seq[A]) {
  def myApply(f: A => A, ith: Int): Seq[A] =
    seq.updated(ith - 1, f(seq(ith - 1)))
}

使用例:

scala> (1 to 3).toList.myApply(_ + 10, ith = 2)
res: Seq[Int] = List(1, 12, 3)

試みられた実際の解決策:

implicit class Seq_[A, Repr <: SeqLike[A, Repr]](seq: Repr) {
  def myApply[B >: A, That](f: A => B, ith: Int)
                           (implicit bf: CanBuildFrom[Repr, B, That]): That =
    seq.updated(ith - 1, f(seq(ith - 1)))
}

残念ながら、暗黙的は機能しません。理由はわかりません。

scala> Seq_[Int, List[Int]]((1 to 3).toList).myApply(_ + 10, ith = 2)
res: List[Int] = List(1, 12, 3)

scala> Seq_[Int, List[Int]]((1 to 3).toList).myApply(_.toString + "*", ith = 2)
res: List[Any] = List(1, 2*, 3)

編集:修正しました!

implicit class Seq_[A, Repr](seq: SeqLike[A, Repr]) {
  def myApply[B >: A, That](f: A => B, ith: Int)
                           (implicit bf: CanBuildFrom[Repr, B, That]): That =
    seq.updated(ith - 1, f(seq(ith - 1)))
}

例:

scala> (1 to 3).toList.myApply(_ + 10, ith = 2)
res: List[Int] = List(1, 12, 3)

scala> (1 to 3).toVector.myApply(Math.pow(2, _), ith = 3)
res: scala.collection.immutable.Vector[AnyVal] = Vector(1, 2, 8.0)

しかし、私はあなたがそれを のためにも機能させたいと思っていることに気付きましたArray。それは ではありませんSeqLike

ああ、からへPredefの暗黙的な変換があり、これは のサブタイプであるため、バインドされたビューを使用するだけで済みます。ArrayArrayOpsSeqLike

implicit class Seq_[A, Repr <% SeqLike[A, Repr]](seq: Repr) {
  def myApply[B >: A, That](f: A => B, ith: Int)
                           (implicit bf: CanBuildFrom[Repr, B, That]): That =
    seq.updated(ith - 1, f(seq(ith - 1)))
}

そして最後に、正しい動作が得られます:

scala> (1 to 3).toList.myApply(_ + 10, ith = 2)
res: List[Int] = List(1, 12, 3)

scala> (1 to 3).toArray.myApply(Math.pow(2, _), ith = 3)
res: Array[AnyVal] = Array(1, 2, 8.0)

もう一度編集してください - samthebest は、ビューの境界が非推奨であることを知らせてくれました。そのため、このガイドを使用して、非常に見苦しいコンテキストの境界に置き換えることができます。

implicit class Seq_[A, Repr, 
    S : ({type L[X] = X => SeqLike[A, Repr]})#L](seq: S) {

  def myApply[B >: A, That](f: A => B, ith: Int)
      (implicit bf: CanBuildFrom[Repr, B, That]): That =
    seq.updated(ith - 1, f(seq(ith - 1)))
}
于 2014-09-12T05:07:07.713 に答える
0

暗黙的なメソッドを既存のコレクションに追加するのは非常に複雑です。外部メソッドを使用しても問題ない場合は、これで解決です。ほとんどありませんが、完全ではありません。Scala IDE ワークシートの例

object SeqOps {
  def applyToith(col: Seq[Int], f: Int => Int, ith: Int): Seq[Int] = {
    val indexCol = col.zipWithIndex
    indexCol.map {
      a => if (a._2 == ith) f(a._1) else a._1
    }
  }                                       //> applyToith: (col: Seq[Int], f: Int => Int, ith: Int)Seq[Int]

  def f(i: Int) = i + 10                  //> f: (i: Int)Int
  val l = List(1, 2, 3)                   //> l  : List[Int] = List(1, 2, 3)
  applyToith(l, f _, 0)                   //> res0: Seq[Int] = List(11, 2, 3)

  val a = Array(1, 2, 3)                  //> a  : Array[Int] = Array(1, 2, 3)
  applyToith(a, f _, 1)                   //> res1: Seq[Int] = ArrayBuffer(1, 12, 3)

  val v = Vector(1, 2, 3)                 //> v  : scala.collection.immutable.Vector[Int] = Vector(1, 2, 3)
  applyToith(v, f _, 2)                   //> res2: Seq[Int] = Vector(1, 2, 13)

}

配列の場合は、Array ではなく ArrayBuffer を返します。他のすべての Seq タイプは適切に機能します。他の多くの組み合わせを試しましたが、この問題を解決するものはありません。

val a : Seq[Int] = Array(1, 2)
a.zipWithIndex

この zipWithIndex は ArrayBuffer を返しますが、val a: Array[Int]使用されている場合はzipWithIndex配列を返します。

Java配列をコレクションに後付けするという気まぐれだと思います。

于 2014-09-12T05:10:44.087 に答える