更新序列中的多个值

时间:2014-08-22 15:23:33

标签: scala collections immutability

要获得更新了一个值的序列,可以使用

seq.updated(index, value)

我想为一系列元素设置一个新值。是否有图书馆功能?我目前使用以下功能:

def updatedSlice[A](seq: List[A], ind: Iterable[Int], value: A): List[A] = 
    if (ind.isEmpty) seq
    else updatedSlice(seq.updated(ind.head, value), ind.tail, value)

除了编写函数之外,这似乎效率低下,并且仅适用于列表,而不是SeqString的任意子类。所以,

  • 有执行它的方法吗?
  • 如何对函数进行参数化以获取(并返回)Seq[A]的某些子类?

2 个答案:

答案 0 :(得分:2)

计算机上没有人说过:

scala> (1 to 10).toSeq patch (3, (1 to 5), 3)
res0: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 1, 2, 3, 4, 5, 7, 8, 9, 10)

保存@Marth的绿色支票。

请注意,他们仍在努力。

https://issues.scala-lang.org/browse/SI-8474

其中提到了一些不经常使用的API。

更新:我第二次看了一眼这个问题,看到我误解了它,哦,好吧:

scala> implicit class x[A](as: Seq[A]) {
     | def updatedAt(is: collection.Traversable[Int], a: A) = {
     | (as /: is) { case (xx, i) => xx updated (i, a) } } }
defined class x

scala> (1 to 10) updatedAt (Seq(3,6,9), 0)
res9: Seq[Int] = Vector(1, 2, 3, 0, 5, 6, 0, 8, 9, 0)

只是轻松一轮的高尔夫球。

更新:s / relax / annoying

看起来它需要更多类型参数,但我没有时间片。

scala> implicit class slicer[A, B[_] <: Seq[_]](as: B[A]) {
     | def updatedAt[That<:B[_]](is: Traversable[Int], a: A)(implicit cbf: CanBuildFrom[B[A], A, That]) =
     | (as /: is) { case (x,i) => x updated[A,That] (i,a) }}
<console>:15: error: type arguments [A,That] conform to the bounds of none of the overloaded alternatives of
 value updated: [B >: _$1, That](index: Int, elem: B)(implicit bf: scala.collection.generic.CanBuildFrom[Seq[_$1],B,That])That <and> [B >: A, That](index: Int, elem: B)(implicit bf: scala.collection.generic.CanBuildFrom[Repr,B,That])That
       (as /: is) { case (x,i) => x updated[A,That] (i,a) }}
                                    ^

谁知道更新过载?

我最喜欢的Odersky引用:

  

我玩它直到它太繁琐了。

答案 1 :(得分:1)

据我所知,没有直接提供此功能的组合器。

对于Seq部分,它仅适用于List,因为您将List作为参数。拿一个Seq,返回一个Seq,你已经少了一个问题。

此外,如果IndexOutOfBounds包含的索引大于或等于ind长度,则您的实现会引发seq异常。

这是一个替代实现(使用Set表示O(1)contains

def updatedAtIndexes[A](seq: Seq[A], ind: Set[Int], value: A): Seq[A] = seq.zipWithIndex.map {
  case (el, i) if ind.contains(i) => value
  case (el, _) => el
}

实施例

updatedAtIndexes(List(1, 2, 3, 4, 5), Set(0, 2), 42) // List(42, 2, 42, 4)

您甚至可以使用简单的隐式类使其更漂亮:

implicit class MyPimpedSeq[A](seq: Seq[A]) {
  def updatedAtIndexes(ind: Set[Int], value: A): Seq[A] = seq.zipWithIndex.map {
    case (el, i) if ind.contains(i) => value
    case (el, _) => el
  }
}

实施例

List(1, 2, 3, 4).updatedAtIndexes(Set(0, 2), 42) // List(42, 2, 42, 4)
Vector(1, 2, 3).updatedAtIndexes(Set(1, 2, 3), 42) // Vector(1, 42, 42)