Skip to content

Commit d7281b6

Browse files
authored
Merge pull request scala/scala#7033 from szeiger/issue/11063
Add lazyZip to ArrayOps and StringOps
2 parents 50e6f42 + 01f2958 commit d7281b6

File tree

5 files changed

+79
-46
lines changed

5 files changed

+79
-46
lines changed

library/src/scala/collection/ArrayOps.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,25 @@ final class ArrayOps[A](val xs: Array[A]) extends AnyVal {
903903
b.result()
904904
}
905905

906+
/** Analogous to `zip` except that the elements in each collection are not consumed until a strict operation is
907+
* invoked on the returned `LazyZip2` decorator.
908+
*
909+
* Calls to `lazyZip` can be chained to support higher arities (up to 4) without incurring the expense of
910+
* constructing and deconstructing intermediary tuples.
911+
*
912+
* {{{
913+
* val xs = List(1, 2, 3)
914+
* val res = (xs lazyZip xs lazyZip xs lazyZip xs).map((a, b, c, d) => a + b + c + d)
915+
* // res == List(4, 8, 12)
916+
* }}}
917+
*
918+
* @param that the iterable providing the second element of each eventual pair
919+
* @tparam B the type of the second element in each eventual pair
920+
* @return a decorator `LazyZip2` that allows strict operations to be performed on the lazily evaluated pairs
921+
* or chained calls to `lazyZip`. Implicit conversion to `Iterable[(A, B)]` is also supported.
922+
*/
923+
def lazyZip[B](that: Iterable[B]): LazyZip2[A, B, Array[A]] = new LazyZip2(xs, immutable.ArraySeq.unsafeWrapArray(xs), that)
924+
906925
/** Returns an array formed from this array and another iterable collection
907926
* by combining corresponding elements in pairs.
908927
* If one of the two collections is shorter than the other,

library/src/scala/collection/Iterable.scala

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,25 @@ trait Iterable[+A] extends IterableOnce[A] with IterableOps[A, Iterable, Iterabl
8181
* by all elements separated by commas and enclosed in parentheses.
8282
*/
8383
override def toString = mkString(className + "(", ", ", ")")
84+
85+
/** Analogous to `zip` except that the elements in each collection are not consumed until a strict operation is
86+
* invoked on the returned `LazyZip2` decorator.
87+
*
88+
* Calls to `lazyZip` can be chained to support higher arities (up to 4) without incurring the expense of
89+
* constructing and deconstructing intermediary tuples.
90+
*
91+
* {{{
92+
* val xs = List(1, 2, 3)
93+
* val res = (xs lazyZip xs lazyZip xs lazyZip xs).map((a, b, c, d) => a + b + c + d)
94+
* // res == List(4, 8, 12)
95+
* }}}
96+
*
97+
* @param that the iterable providing the second element of each eventual pair
98+
* @tparam B the type of the second element in each eventual pair
99+
* @return a decorator `LazyZip2` that allows strict operations to be performed on the lazily evaluated pairs
100+
* or chained calls to `lazyZip`. Implicit conversion to `Iterable[(A, B)]` is also supported.
101+
*/
102+
def lazyZip[B](that: Iterable[B]): LazyZip2[A, B, this.type] = new LazyZip2(this, this, that)
84103
}
85104

86105
/** Base trait for Iterable operations
@@ -846,9 +865,7 @@ object IterableOps {
846865
}
847866

848867
@SerialVersionUID(3L)
849-
object Iterable extends IterableFactory.Delegate[Iterable](immutable.Iterable) {
850-
implicit def toLazyZipOps[A, CC[X] <: Iterable[X]](that: CC[A]): LazyZipOps[A, CC[A]] = new LazyZipOps(that)
851-
}
868+
object Iterable extends IterableFactory.Delegate[Iterable](immutable.Iterable)
852869

853870
/** Explicit instantiation of the `Iterable` trait to reduce class file size in subclasses. */
854871
@SerialVersionUID(3L)

library/src/scala/collection/LazyZipOps.scala

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,8 @@ package scala.collection
22

33
import scala.language.implicitConversions
44

5-
final class LazyZipOps[A, C1 <: Iterable[A]] private[collection](val `this`: C1) extends AnyVal {
6-
7-
/** Analogous to `zip` except that the elements in each collection are not consumed until a strict operation is
8-
* invoked on the returned `LazyZip2` decorator.
9-
*
10-
* Calls to `lazyZip` can be chained to support higher arities (up to 4) without incurring the expense of
11-
* constructing and deconstructing intermediary tuples.
12-
*
13-
* {{{
14-
* val xs = List(1, 2, 3)
15-
* val res = (xs lazyZip xs lazyZip xs lazyZip xs).map((a, b, c, d) => a + b + c + d)
16-
* // res == List(4, 8, 12)
17-
* }}}
18-
*
19-
* @param that the iterable providing the second element of each eventual pair
20-
* @tparam B the type of the second element in each eventual pair
21-
* @return a decorator `LazyZip2` that allows strict operations to be performed on the lazily evaluated pairs
22-
* or chained calls to `lazyZip`. Implicit conversion to `Iterable[(A, B)]` is also supported.
23-
*/
24-
def lazyZip[B](that: Iterable[B]): LazyZip2[A, B, C1] = new LazyZip2(`this`, that)
25-
}
26-
275
/** Decorator representing lazily zipped pairs. */
28-
final class LazyZip2[El1, El2, C1 <: Iterable[El1]] private[collection](coll1: C1, coll2: Iterable[El2]) {
6+
final class LazyZip2[+El1, +El2, C1] private[collection](src: C1, coll1: Iterable[El1], coll2: Iterable[El2]) {
297

308
/** Zips `that` iterable collection with an existing `LazyZip2`. The elements in each collection are
319
* not consumed until a strict operation is invoked on the returned `LazyZip3` decorator.
@@ -35,10 +13,10 @@ final class LazyZip2[El1, El2, C1 <: Iterable[El1]] private[collection](coll1: C
3513
* @return a decorator `LazyZip3` that allows strict operations to be performed on the lazily evaluated tuples or
3614
* chained calls to `lazyZip`. Implicit conversion to `Iterable[(El1, El2, B)]` is also supported.
3715
*/
38-
def lazyZip[B](that: Iterable[B]): LazyZip3[El1, El2, B, C1] = new LazyZip3(coll1, coll2, that)
16+
def lazyZip[B](that: Iterable[B]): LazyZip3[El1, El2, B, C1] = new LazyZip3(src, coll1, coll2, that)
3917

4018
def map[B, C](f: (El1, El2) => B)(implicit bf: BuildFrom[C1, B, C]): C = {
41-
bf.fromSpecificIterable(coll1)(new AbstractView[B] {
19+
bf.fromSpecificIterable(src)(new AbstractView[B] {
4220
def iterator = new AbstractIterator[B] {
4321
private[this] val elems1 = coll1.iterator
4422
private[this] val elems2 = coll2.iterator
@@ -51,7 +29,7 @@ final class LazyZip2[El1, El2, C1 <: Iterable[El1]] private[collection](coll1: C
5129
}
5230

5331
def flatMap[B, C](f: (El1, El2) => Iterable[B])(implicit bf: BuildFrom[C1, B, C]): C = {
54-
bf.fromSpecificIterable(coll1)(new AbstractView[B] {
32+
bf.fromSpecificIterable(src)(new AbstractView[B] {
5533
def iterator = new AbstractIterator[B] {
5634
private[this] val elems1 = coll1.iterator
5735
private[this] val elems2 = coll2.iterator
@@ -70,7 +48,7 @@ final class LazyZip2[El1, El2, C1 <: Iterable[El1]] private[collection](coll1: C
7048
}
7149

7250
def filter[C](p: (El1, El2) => Boolean)(implicit bf: BuildFrom[C1, (El1, El2), C]): C = {
73-
bf.fromSpecificIterable(coll1)(new AbstractView[(El1, El2)] {
51+
bf.fromSpecificIterable(src)(new AbstractView[(El1, El2)] {
7452
def iterator = new AbstractIterator[(El1, El2)] {
7553
private[this] val elems1 = coll1.iterator
7654
private[this] val elems2 = coll2.iterator
@@ -136,9 +114,10 @@ object LazyZip2 {
136114

137115

138116
/** Decorator representing lazily zipped triples. */
139-
final class LazyZip3[El1, El2, El3, C1 <: Iterable[El1]] private[collection](coll1: C1,
140-
coll2: Iterable[El2],
141-
coll3: Iterable[El3]) {
117+
final class LazyZip3[+El1, +El2, +El3, C1] private[collection](src: C1,
118+
coll1: Iterable[El1],
119+
coll2: Iterable[El2],
120+
coll3: Iterable[El3]) {
142121

143122
/** Zips `that` iterable collection with an existing `LazyZip3`. The elements in each collection are
144123
* not consumed until a strict operation is invoked on the returned `LazyZip4` decorator.
@@ -148,10 +127,10 @@ final class LazyZip3[El1, El2, El3, C1 <: Iterable[El1]] private[collection](col
148127
* @return a decorator `LazyZip4` that allows strict operations to be performed on the lazily evaluated tuples.
149128
* Implicit conversion to `Iterable[(El1, El2, El3, B)]` is also supported.
150129
*/
151-
def lazyZip[B](that: Iterable[B]): LazyZip4[El1, El2, El3, B, C1] = new LazyZip4(coll1, coll2, coll3, that)
130+
def lazyZip[B](that: Iterable[B]): LazyZip4[El1, El2, El3, B, C1] = new LazyZip4(src, coll1, coll2, coll3, that)
152131

153132
def map[B, C](f: (El1, El2, El3) => B)(implicit bf: BuildFrom[C1, B, C]): C = {
154-
bf.fromSpecificIterable(coll1)(new AbstractView[B] {
133+
bf.fromSpecificIterable(src)(new AbstractView[B] {
155134
def iterator = new AbstractIterator[B] {
156135
private[this] val elems1 = coll1.iterator
157136
private[this] val elems2 = coll2.iterator
@@ -165,7 +144,7 @@ final class LazyZip3[El1, El2, El3, C1 <: Iterable[El1]] private[collection](col
165144
}
166145

167146
def flatMap[B, C](f: (El1, El2, El3) => Iterable[B])(implicit bf: BuildFrom[C1, B, C]): C = {
168-
bf.fromSpecificIterable(coll1)(new AbstractView[B] {
147+
bf.fromSpecificIterable(src)(new AbstractView[B] {
169148
def iterator = new AbstractIterator[B] {
170149
private[this] val elems1 = coll1.iterator
171150
private[this] val elems2 = coll2.iterator
@@ -185,7 +164,7 @@ final class LazyZip3[El1, El2, El3, C1 <: Iterable[El1]] private[collection](col
185164
}
186165

187166
def filter[C](p: (El1, El2, El3) => Boolean)(implicit bf: BuildFrom[C1, (El1, El2, El3), C]): C = {
188-
bf.fromSpecificIterable(coll1)(new AbstractView[(El1, El2, El3)] {
167+
bf.fromSpecificIterable(src)(new AbstractView[(El1, El2, El3)] {
189168
def iterator = new AbstractIterator[(El1, El2, El3)] {
190169
private[this] val elems1 = coll1.iterator
191170
private[this] val elems2 = coll2.iterator
@@ -259,13 +238,14 @@ object LazyZip3 {
259238

260239

261240
/** Decorator representing lazily zipped 4-tuples. */
262-
final class LazyZip4[El1, El2, El3, El4, C1 <: Iterable[El1]] private[collection](coll1: C1,
263-
coll2: Iterable[El2],
264-
coll3: Iterable[El3],
265-
coll4: Iterable[El4]) {
241+
final class LazyZip4[+El1, +El2, +El3, +El4, C1] private[collection](src: C1,
242+
coll1: Iterable[El1],
243+
coll2: Iterable[El2],
244+
coll3: Iterable[El3],
245+
coll4: Iterable[El4]) {
266246

267247
def map[B, C](f: (El1, El2, El3, El4) => B)(implicit bf: BuildFrom[C1, B, C]): C = {
268-
bf.fromSpecificIterable(coll1)(new AbstractView[B] {
248+
bf.fromSpecificIterable(src)(new AbstractView[B] {
269249
def iterator = new AbstractIterator[B] {
270250
private[this] val elems1 = coll1.iterator
271251
private[this] val elems2 = coll2.iterator
@@ -280,7 +260,7 @@ final class LazyZip4[El1, El2, El3, El4, C1 <: Iterable[El1]] private[collection
280260
}
281261

282262
def flatMap[B, C](f: (El1, El2, El3, El4) => Iterable[B])(implicit bf: BuildFrom[C1, B, C]): C = {
283-
bf.fromSpecificIterable(coll1)(new AbstractView[B] {
263+
bf.fromSpecificIterable(src)(new AbstractView[B] {
284264
def iterator = new AbstractIterator[B] {
285265
private[this] val elems1 = coll1.iterator
286266
private[this] val elems2 = coll2.iterator
@@ -301,7 +281,7 @@ final class LazyZip4[El1, El2, El3, El4, C1 <: Iterable[El1]] private[collection
301281
}
302282

303283
def filter[C](p: (El1, El2, El3, El4) => Boolean)(implicit bf: BuildFrom[C1, (El1, El2, El3, El4), C]): C = {
304-
bf.fromSpecificIterable(coll1)(new AbstractView[(El1, El2, El3, El4)] {
284+
bf.fromSpecificIterable(src)(new AbstractView[(El1, El2, El3, El4)] {
305285
def iterator = new AbstractIterator[(El1, El2, El3, El4)] {
306286
private[this] val elems1 = coll1.iterator
307287
private[this] val elems2 = coll2.iterator

library/src/scala/collection/Map.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,6 @@ object MapOps {
332332
*/
333333
@SerialVersionUID(3L)
334334
object Map extends MapFactory.Delegate[Map](immutable.Map) {
335-
implicit def toLazyZipOps[K, V, CC[X, Y] <: Iterable[(X, Y)]](that: CC[K, V]): LazyZipOps[(K, V), CC[K, V]] = new LazyZipOps(that)
336-
337335
private val DefaultSentinel: AnyRef = new AnyRef
338336
}
339337

library/src/scala/collection/StringOps.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,6 +1289,25 @@ final class StringOps(private val s: String) extends AnyVal {
12891289
(res1.toString, res2.toString)
12901290
}
12911291

1292+
/** Analogous to `zip` except that the elements in each collection are not consumed until a strict operation is
1293+
* invoked on the returned `LazyZip2` decorator.
1294+
*
1295+
* Calls to `lazyZip` can be chained to support higher arities (up to 4) without incurring the expense of
1296+
* constructing and deconstructing intermediary tuples.
1297+
*
1298+
* {{{
1299+
* val xs = List(1, 2, 3)
1300+
* val res = (xs lazyZip xs lazyZip xs lazyZip xs).map((a, b, c, d) => a + b + c + d)
1301+
* // res == List(4, 8, 12)
1302+
* }}}
1303+
*
1304+
* @param that the iterable providing the second element of each eventual pair
1305+
* @tparam B the type of the second element in each eventual pair
1306+
* @return a decorator `LazyZip2` that allows strict operations to be performed on the lazily evaluated pairs
1307+
* or chained calls to `lazyZip`. Implicit conversion to `Iterable[(A, B)]` is also supported.
1308+
*/
1309+
def lazyZip[B](that: Iterable[B]): LazyZip2[Char, B, String] = new LazyZip2(s, new WrappedString(s), that)
1310+
12921311

12931312
/* ************************************************************************************************************
12941313
The remaining methods are provided for completeness but they delegate to WrappedString implementations which

0 commit comments

Comments
 (0)