Skip to content

Commit 6fc3f9d

Browse files
committed
add cycle method to LazyList
1 parent 4df7c68 commit 6fc3f9d

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Scala (https://www.scala-lang.org)
3+
*
4+
* Copyright EPFL and Lightbend, Inc.
5+
*
6+
* Licensed under Apache License 2.0
7+
* (http://www.apache.org/licenses/LICENSE-2.0).
8+
*
9+
* See the NOTICE file distributed with this work for
10+
* additional information regarding copyright ownership.
11+
*/
12+
13+
package scala.collection.immutable
14+
15+
object LazyListExtensions {
16+
17+
implicit class LazyListCycle[T](ll: LazyList[T]) {
18+
/**
19+
* When called on a finite `LazyList`, returns a circular structure
20+
* that endlessly repeats the elements in the input.
21+
* The result is a true cycle occupying only constant memory.
22+
*/
23+
def cycle: LazyList[T] =
24+
if (ll.isEmpty)
25+
LazyList.empty
26+
else {
27+
lazy val result: LazyList[T] = ll #::: result
28+
result
29+
}
30+
}
31+
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Scala (https://www.scala-lang.org)
3+
*
4+
* Copyright EPFL and Lightbend, Inc.
5+
*
6+
* Licensed under Apache License 2.0
7+
* (http://www.apache.org/licenses/LICENSE-2.0).
8+
*
9+
* See the NOTICE file distributed with this work for
10+
* additional information regarding copyright ownership.
11+
*/
12+
13+
package scala.collection.immutable
14+
15+
import org.junit.Assert._
16+
import org.junit.Test
17+
18+
import LazyListExtensions._
19+
20+
class TestLazyListExtensions {
21+
@Test
22+
def testEmpty1(): Unit = {
23+
val xs = LazyList.empty // realized
24+
val cyc = xs.cycle
25+
assertTrue(cyc.isEmpty)
26+
assertTrue(cyc.size == 0)
27+
assertEquals(Nil, cyc.toList)
28+
}
29+
@Test
30+
def testEmpty2(): Unit = {
31+
val xs = LazyList() // not realized
32+
val cyc = xs.cycle
33+
assertTrue(cyc.isEmpty)
34+
assertTrue(cyc.size == 0)
35+
assertEquals(Nil, cyc.toList)
36+
}
37+
@Test
38+
def testNonEmpty(): Unit = {
39+
val xs = LazyList(1, 2, 3)
40+
val cyc = xs.cycle
41+
assertFalse(cyc.isEmpty)
42+
assertEquals(LazyList(1, 2, 3, 1, 2, 3, 1, 2), cyc.take(8))
43+
}
44+
@Test
45+
def testToString(): Unit = {
46+
assertEquals("LazyList()",
47+
LazyList.empty.cycle.toString)
48+
assertEquals("LazyList(<not computed>)",
49+
LazyList(1, 2, 3).cycle.toString)
50+
// note cycle detection here!
51+
assertEquals("LazyList(1, 2, 3, <cycle>)",
52+
LazyList(1, 2, 3).cycle.force.toString)
53+
}
54+
@Test
55+
def testRepeats(): Unit = {
56+
val xs = LazyList(1, 2, 3)
57+
val cyc = xs.cycle
58+
assertFalse(cyc.isEmpty)
59+
assertEquals(LazyList(1, 2, 3, 1, 2, 3, 1, 2), cyc.take(8))
60+
}
61+
@Test
62+
def testConstantMemory1(): Unit = {
63+
val xs = LazyList(1, 2, 3)
64+
val cyc = xs.cycle
65+
assertTrue(cyc.tail eq cyc.tail.tail.tail.tail)
66+
assertTrue(cyc.tail eq cyc.drop(4)) // TODO: fails
67+
assertTrue(cyc eq cyc.tail.tail.tail) // TODO: fails
68+
assertTrue(cyc eq cyc.drop(3)) // TODO: fails
69+
assertTrue(cyc eq cyc.drop(3)) // TODO: fails
70+
}
71+
@Test
72+
def testConstantMemory2(): Unit = {
73+
var counter = 0
74+
def count(): Int = { counter += 1; counter }
75+
val xs = count() #:: count() #:: count() #:: LazyList.empty
76+
val cyc = xs.cycle
77+
assertEquals(1, counter)
78+
assertEquals(10, cyc.take(10).size)
79+
assertEquals(3, counter)
80+
}
81+
}

0 commit comments

Comments
 (0)