Slice notation in Scala?

后端 未结 4 2072
轮回少年
轮回少年 2020-12-14 15:38

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.

相关标签:
4条回答
  • 2020-12-14 16:00

    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.

    0 讨论(0)
  • 2020-12-14 16:07
    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)
    
    0 讨论(0)
  • 2020-12-14 16:14

    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

    0 讨论(0)
  • 2020-12-14 16:18

    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.

    0 讨论(0)
提交回复
热议问题