2017-02-07 3 views
2

以上であるとき、これはScalaのコレクションAPIのsliding()です:Scalaのコレクションのスライドは、()矛盾しているウィンドウサイズがステップ

/** Groups elements in fixed size blocks by passing a "sliding window" 
    * over them (as opposed to partitioning them, as is done in grouped.) 
    * @see [[scala.collection.Iterator]], method `sliding` 
    * 
    * @param size the number of elements per group 
    * @param step the distance between the first elements of successive 
    *   groups 
    * @return An iterator producing ${coll}s of size `size`, except the 
    *   last and the only element will be truncated if there are 
    *   fewer elements than size. 
    */ 
    def sliding(size: Int, step: Int): Iterator[Repr] = 

これを理解する簡単な方法は、スライドは、単に(0 until this.length by step).map(i => slice(i, i + size))であるということです。

object SlidingTest extends App { 
    val n = 10 

    val r1 = 0 until n 

    val r2 = new Range(start = 0, end = n, step = 1) { 
    override def sliding(size: Int, step: Int) = 
    (indices by step).iterator.map(i => slice(i, i + size)) 
    } 

    for { 
    i <- 1 to 2*n 
    j <- 1 to 2*n 
    s1 = r1.sliding(i, j).toList.map(_.toList) 
    s2 = r2.sliding(i, j).toList.map(_.toList) 
    if s1 != s2 
    } println(s"Sliding fail for size=$i and step=$j: [s1=$s1; s2=$s2]") 
} 

は、具体的に r1 = 0 until 10を考慮してくださいとき size > stepしかし、この解釈は動作しません。 (すなわち、最後の切り捨てのスライスが欠落している)

List(List(0, 1), List(1, 2), List(2, 3), List(3, 4), List(4, 5), List(5, 6), List(6, 7), List(7, 8), List(8, 9)) 

List(List(0, 1), List(1, 2), List(2, 3), List(3, 4), List(4, 5), List(5, 6), List(6, 7), List(7, 8), List(8, 9), List(9)) 

しかし、実際にはこれです:ドキュメントによると、r1.sliding(size = 2, step = 1)はこれでなければなりません。

Scaladocからコピーされた別のスニペット:

/** Returns an iterator which presents a "sliding window" view of 
    * another iterator. The first argument is the window size, and 
    * the second is how far to advance the window on each iteration; 
    * defaults to `1`. Example usages: 
    * {{{ 
    * // Returns List(List(1, 2, 3), List(2, 3, 4), List(3, 4, 5)) 
    * (1 to 5).iterator.sliding(3).toList 
    * // Returns List(List(1, 2, 3, 4), List(4, 5)) 
    * (1 to 5).iterator.sliding(4, 3).toList 
    * // Returns List(List(1, 2, 3, 4)) 
    * (1 to 5).iterator.sliding(4, 3).withPartial(false).toList 
    * // Returns List(List(1, 2, 3, 4), List(4, 5, 20, 25)) 
    * // Illustrating that withPadding's argument is by-name. 
    * val it2 = Iterator.iterate(20)(_ + 5) 
    * (1 to 5).iterator.sliding(4, 3).withPadding(it2.next).toList 
    * }}} 
    * 
    * @note Reuse: $consumesAndProducesIterator 
    */ 
    def sliding[B >: A](size: Int, step: Int = 1): GroupedIterator[B] = 
    new GroupedIterator[B](self, size, step) 

は私が間違って何をしているのですか?

+0

サイズ 'より' collection.size'または少ない要素より少ない要素@DanGetz '関数の引数? 'size = 2、step = 7'でこの関数を試してみると' collection.size'を意味すると思います。 – pathikrit

+0

私はこのチャットにはあまり従いませんでしたが、明らかになったら答えに文言を投稿します。 –

+0

@DanGetz - フォローアップに感謝しますが、som-snyttの説明が役立ちます。 '最後の要素(唯一の要素かもしれない)がグループ化されるべき残りの要素の数よりも少ない場合には切り捨てられるように、'最後の要素と唯一の要素がサイズよりも少ない要素があれば切り捨てられる ' */ – pathikrit

答えて

0

、私は次のようにsliceの面でslidingを表現する方法を見つけました:

override def sliding(window: Int, step: Int) = { 
    require(window > 0 && step > 0, s"window=$window and step=$step, but both must be positive") 
    val lag = (window - step) max 0 
    Iterator.range(start = 0, end = length - lag, step = step).map(i => slice(i, i + window)) 
} 
4

要素をグループ化し、すべてがグループ化されると停止します。

可能なステップごとにグループ化されません。あなたの例では

scala> (1 to 100).sliding(size=100,step=1).toList.size 
res0: Int = 1 

scala> (1 to 100).sliding(size=99,step=1).toList.size 
res1: Int = 2 

、あなたはコレクションはすでに徹底的にグループ化されているにもかかわらず、それは9と、余分なグループを作成することを期待しています。

また要素が部分的にグループを形成する例を示しています。

scala> (1 to 5).sliding(size=4,step=3).toList 
res4: List[scala.collection.immutable.IndexedSeq[Int]] = List(Vector(1, 2, 3, 4), Vector(4, 5)) 

5がグループ化されていないままなので、余分なグループが必要です。

編集:Scaladocの可能rewording:

$ {コル} Sサイズsizeのを産生イテレータ、ある場合には(唯一の要素であってもよい)最後の要素 が切り捨てられます以外 より少なく、グループ化される要素は残りのsizeです。 @のSOM-snyttの答えに基づいて

+2

https://github.com/scala/scala/pull/5679 –