2014-09-12 1 views
3

Для любого заданного списка или массива, напримерПрименить функцию к одному элементу только в списке или массива в Scala

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

и данной функции, отображающая и на тип коллекции, например

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

как применять f к-го элемента list или array так что

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

, а также

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

ответ

7

Т.Л., д-р

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) 

Edit: Фиксированный это!

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, так что позвольте мне думать, еще немного ...

Ah, Predef имеет неявное преобразование от Array до ArrayOps, что является подтипом SeqLike, поэтому нам просто нужно, чтобы u с точки зрения.

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

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

«Семя» вверх, надеясь, что вы выработаете тип args. Так легко записывать часы на коллекциях. –

+0

Когда дело доходит до implicits, которые не применяются, я никогда не могу сказать, является ли это моей ошибкой или компилятором, поэтому трудно узнать, когда ее вызывать. –

+0

Я чувствую вашу боль. –

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) 

} 

В случае массива, он возвращает ArrayBuffer вместо Array. Для всех других типов Seq работает правильно. Я пробовал много других комбинаций, но ничего не исправляет эту проблему.

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

Это zipWithIndex возвращает ArrayBuffer но если val a: Array[Int] используется, zipWithIndex возвращает массив.

Капризы для ретро-сборных массивов Java в коллекциях, я думаю.

3

Кто-то спросил о патче, так что, может быть, это дубликат:

scala> val list = (1 to 3).toList 
list: List[Int] = List(1, 2, 3) 

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

scala> def g(is: Seq[Int], f: Int => Int, i: Int) = is.patch(i, Seq(f(is(i))), 1) 
g: (is: Seq[Int], f: Int => Int, i: Int)Seq[Int] 

scala> g(list, f, 1) 
res1: Seq[Int] = List(1, 12, 3) 

Обобщая капельку:

scala> def g(is: collection.Seq[Int], f: Int => Int, i: Int, count: Int = 1) = is.patch(i, is.slice(i, i + count) map f, count) 
g: (is: Seq[Int], f: Int => Int, i: Int, count: Int)Seq[Int] 

scala> g(list, f, 1) 
res2: Seq[Int] = List(1, 12, 3) 

scala> g(list, f, 1, 2) 
res3: Seq[Int] = List(1, 12, 13) 

Это был мой первый идти, а предлагающее Крис:

scala> def g(is: collection.mutable.Seq[Int], f: Int => Int, i: Int) = is(i) = f(is(i)) 
g: (is: scala.collection.mutable.Seq[Int], f: Int => Int, i: Int)Unit 

scala> val as = (1 to 10).toArray 
as: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 

scala> g(as, f, 1) 

scala> as 
res7: Array[Int] = Array(1, 12, 3, 4, 5, 6, 7, 8, 9, 10) 

Так как Крис говорил:

scala> def g(is: collection.Seq[Int], f: Int => Int, i: Int) = is.updated(i, f(is(i))) 
g: (is: Seq[Int], f: Int => Int, i: Int)Seq[Int] 

И спокойной ночи, Грейси.

+0

'updated' будет проще. –

+0

Для изменчивых ... –

+0

Huh?' Updated' находится на 'collection.Seq'. –