Is there something similar to the slice notation in Python in Scala?
I think this is really a useful operation that should be incorporated in all languages.
Is there something similar to the slice notation in Python in Scala?
I think this is really a useful operation that should be incorporated in all languages.
scala> import collection.IterableLike
import collection.IterableLike
scala> implicit def pythonicSlice[A, Repr](coll: IterableLike[A, Repr]) = new {
| def apply(subrange: (Int, Int)): Repr = coll.slice(subrange._1, subrange._2)
| }
pythonicSlice: [A,Repr](coll: scala.collection.IterableLike[A,Repr])java.lang.Object{def apply(subrange: (Int, Int)): Repr}
scala> val list = List(3, 4, 11, 78, 3, 9)
list: List[Int] = List(3, 4, 11, 78, 3, 9)
scala> list(2 -> 5)
res4: List[Int] = List(11, 78, 3)
Will this do?
Disclaimer: Not properly generalized.
EDIT:
scala> case class PRange(start: Int, end: Int, step: Int = 1)
defined class PRange
scala> implicit def intWithTildyArrow(i: Int) = new {
| def ~>(j: Int) = PRange(i, j)
| }
intWithTildyArrow: (i: Int)java.lang.Object{def ~>(j: Int): PRange}
scala> implicit def prangeWithTildyArrow(p: PRange) = new {
| def ~>(step: Int) = p.copy(step = step)
| }
prangeWithTildyArrow: (p: PRange)java.lang.Object{def ~>(step: Int): PRange}
scala> implicit def pSlice[A](coll: List[A]) = new {
| def apply(prange: PRange) = {
| import prange._
| coll.slice(start, end).grouped(step).toList.map(_.head)
| }
| }
pSlice: [A](coll: List[A])java.lang.Object{def apply(prange: PRange): List[A]}
scala> val xs = List.range(1, 10)
xs: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> xs(3 ~> 9)
res32: List[Int] = List(4, 5, 6, 7, 8, 9)
scala> xs(3 ~> 9 ~> 2)
res33: List[Int] = List(4, 6, 8)
Equivalent method in Scala (with a slightly different syntax) exists for all kinds of sequences:
scala> "Hello world" slice(0,4)
res0: String = Hell
scala> (1 to 10) slice(3,5)
res1: scala.collection.immutable.Range = Range(4, 5)
The biggest difference compared to slicing in Python is that start and end indices are mandatory in Scala.
See the ScalaAPI here
So not the same notational convenience, but the operation is there
def slice (from: Int, until: Int) : Seq[A]
Selects an interval of elements.
Selects an interval of elements.
Note: c.slice(from, to) is equivalent to (but possibly more efficient than) c.drop(from).take(to - from)
from the index of the first returned element in this sequence. until the index one past the last returned element in this sequence.
returns
a sequence containing the elements starting at index from and extending up to (but not including) index until of this sequence.
definition classes: IterableLike → TraversableLike
Note that this does not quite work by using apply, but it generalizes to lists, strings, arrays, etc:
implicit def it2sl[Repr <% scala.collection.IterableLike[_, Repr]](cc: Repr) = new {
def ~>(i : Int, j : Int) : Repr = cc.slice(i,j)
}
The usage is:
scala> "Hello World" ~> (3, 5)
res1: java.lang.String = lo
scala> List(1, 2, 3, 4) ~> (0, 2)
res2: List[Int] = List(1, 2)
scala> Array('a', 'b', 'c', 'd') ~> (1, 3)
res3: Array[Char] = Array(b, c)
You might want to rename the method to something else that takes your fancy. Except apply (because there is already a conversion from String to StringLike which decorates String with an apply method - similarly with ArrayOps - and there is already an apply method on other collection types such as List).
Thanks for Daniel for the hint to use a view bound.