【问题标题】:Function to shift a range移动范围的功能
【发布时间】:2018-04-02 17:07:42
【问题描述】:

是否有一个现有的函数可以将Range 转换为另一个Range,例如

val r = 1 to 5
val s = r.map(_ + 2)  // produces Vector(3, 4, 5, 6, 7)

我想得到3 to 7

【问题讨论】:

  • 拥有该功能会有什么好处。 As r map(_+2) == (3 to 8) ?

标签: scala scala-collections


【解决方案1】:

这是我将如何实现它:

implicit class RangeHasShift(val r: Range) extends AnyVal {
  def shift(n: Int): Range = {
    val start1 = r.start + n
    val end1   = r.end   + n

    // overflow check
    if ((n > 0 && (start1 < r.start || end1 < r.end)) ||
        (n < 0 && (start1 > r.start || end1 > r.end)))
      throw new IllegalArgumentException(s"$r.shift($n) causes number overflow")

    if (r.isInclusive)
      new Range.Inclusive(start1, end1, r.step)
    else
      new Range          (start1, end1, r.step)
  }
}

def check(r: Range) = assert(r == r.shift(123).shift(-123))

check(1 to 10)
check(1 to -1)
check(1 to -1 by -1)
check(1 to 10 by 3)
check(1 until 10)
check(1 until -1)
check(1 until -1 by -1)
check(1 until 10 by 3)

我想知道这是否存在于 API 中的某个地方?

【讨论】:

  • 添加溢出检查有意义吗?
【解决方案2】:

如果您的主要目标不是在移动范围时将所有值都保存在内存中,您可以使用视图:

scala> (1 to 999999999).view.map(_ + 2)
res0: scala.collection.SeqView[Int,Seq[_]] = SeqViewM(...)

这类似于 Range 的旧实现,它返回一个惰性序列。

【讨论】:

  • 不,不幸的是我确实需要维护Range 类型;但感谢您的建议。
【解决方案3】:

另一种返回包含范围的简单方法

val newRange = previousRange.start + shift to previousRange.end + shift

val newRange = Range.inclusive(previousRange.start + shift, previousRange.end + shift)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-25
    • 2021-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多