Skip to content

Commit e3df10a

Browse files
authored
Merge pull request scala#6513 from szeiger/wip/iterableonceops-fold
Add IterableOnceOps.fold
2 parents e8ce7e3 + 8ad4621 commit e3df10a

File tree

7 files changed

+51
-9
lines changed

7 files changed

+51
-9
lines changed

src/library/scala/collection/ArrayOps.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,17 @@ final class ArrayOps[A](val xs: Array[A]) extends AnyVal {
553553
v
554554
}
555555

556+
/** Folds the elements of this array using the specified associative binary operator.
557+
*
558+
* @tparam A1 a type parameter for the binary operator, a supertype of `A`.
559+
* @param z a neutral element for the fold operation; may be added to the result
560+
* an arbitrary number of times, and must not change the result (e.g., `Nil` for list concatenation,
561+
* 0 for addition, or 1 for multiplication).
562+
* @param op a binary operator that must be associative.
563+
* @return the result of applying the fold operator `op` between all the elements and `z`, or `z` if this array is empty.
564+
*/
565+
@`inline` final def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)
566+
556567
/** Builds a new array by applying a function to all elements of this array.
557568
*
558569
* @param f the function to apply to each element.

src/library/scala/collection/IterableOnce.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ final class IterableOnceExtensionMethods[A](private val it: IterableOnce[A]) ext
113113
@deprecated("Use .iterator().foldRight instead of .foldLeft on IterableOnce", "2.13.0")
114114
@`inline` def foldRight[B](z: B)(op: (A, B) => B): B = it.iterator().foldRight(z)(op)
115115

116+
@deprecated("Use .iterator().fold instead of .fold on IterableOnce", "2.13.0")
117+
def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = it.iterator().fold(z)(op)
118+
116119
@deprecated("Use .iterator().foldLeft instead of /: on IterableOnce", "2.13.0")
117120
@`inline` def /: [B](z: B)(op: (B, A) => B): B = foldLeft[B](z)(op)
118121

@@ -465,6 +468,22 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
465468
@deprecated("Use foldRight instead of :\\", "2.13.0")
466469
@`inline` final def :\ [B](z: B)(op: (A, B) => B): B = foldRight[B](z)(op)
467470

471+
/** Folds the elements of this $coll using the specified associative binary operator.
472+
* The default implementation in `IterableOnce` is equivalent to `foldLeft` but may be
473+
* overridden for more efficient traversal orders.
474+
*
475+
* $undefinedorder
476+
* $willNotTerminateInf
477+
*
478+
* @tparam A1 a type parameter for the binary operator, a supertype of `A`.
479+
* @param z a neutral element for the fold operation; may be added to the result
480+
* an arbitrary number of times, and must not change the result (e.g., `Nil` for list concatenation,
481+
* 0 for addition, or 1 for multiplication).
482+
* @param op a binary operator that must be associative.
483+
* @return the result of applying the fold operator `op` between all the elements and `z`, or `z` if this $coll is empty.
484+
*/
485+
def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)
486+
468487
/** Reduces the elements of this $coll using the specified associative binary operator.
469488
*
470489
* $undefinedorder

test/benchmarks/src/main/scala/scala/collection/DistinctBenchmark.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class DistinctBenchmark {
3333
b2 += i.toString
3434
}
3535

36-
val adjustCollectionType = collectionType match {
36+
val adjustCollectionType: (Seq[String] => Seq[String]) = collectionType match {
3737
case "List" => (col: Seq[String]) => col.toList
3838
case "Vector" => (col: Seq[String]) => col.toVector
3939
}

test/benchmarks/src/main/scala/scala/collection/mutable/ArrayOpsBenchmark.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ class ArrayOpsBenchmark {
1818
var size: Int = _
1919
var integers: List[Int] = _
2020
var strings: List[String] = _
21+
var integersA: Array[Int] = _
2122

2223

2324
@Setup(Level.Trial) def initNumbers: Unit = {
2425
integers = (1 to size).toList
2526
strings = integers.map(_.toString)
27+
integersA = integers.toArray
2628
}
2729

2830
@Benchmark def appendInteger(bh: Blackhole): Unit = {
@@ -56,4 +58,12 @@ class ArrayOpsBenchmark {
5658
}
5759
bh.consume(arr)
5860
}
61+
62+
@Benchmark def foldLeftSum(bh: Blackhole): Unit = {
63+
bh.consume(integersA.foldLeft(0){ (z,n) => z + n })
64+
}
65+
66+
@Benchmark def foldSum(bh: Blackhole): Unit = {
67+
bh.consume(integersA.fold(0){ (a,b) => a + b })
68+
}
5969
}

test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapRunner.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ object OpenHashMapRunner extends JmhRunner {
4848

4949

5050
def main(args: Array[String]) {
51-
import scala.collection.JavaConversions._
51+
import scala.collection.JavaConverters._
5252

5353
val opts = new CommandLineOptions(args: _*)
5454
var builder = new OptionsBuilder().parent(opts).jvmArgsPrepend("-Xmx6000m")
@@ -72,7 +72,7 @@ object OpenHashMapRunner extends JmhRunner {
7272
def addToDataset(key: String, result: RunResult): Unit =
7373
datasetByName.getOrElseUpdate(key, SortedSet.empty(ordering)) += result
7474

75-
results.foreach { result =>
75+
results.asScala.foreach { result =>
7676
addToDataset(result.label, result)
7777

7878
// Create another data set for trials that track memory usage

test/benchmarks/src/main/scala/scala/util/matching/RegexUnapplyBenchmark.scala

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,14 @@ class RegexUnapplyBenchmark {
2525
@Benchmark def t8022CharSequence(bh: Blackhole): Unit = {
2626
val full = t8022CharSequenceRegex
2727
val text = " When I use this operator: *"
28-
// Testing 2.10.x compatibility of the return types of unapplySeq
29-
val x :: Nil = full.unapplySeq(text: Any).get
3028
val y :: Nil = full.unapplySeq(text: CharSequence).get
31-
bh.consume(x)
3229
bh.consume(y)
3330
}
3431

3532
@Benchmark def t8022Match(bh: Blackhole): Unit = {
3633
val R = t8022MatchRegex
3734
val matchh = R.findFirstMatchIn("a1").get
38-
// Testing 2.10.x compatibility of the return types of unapplySeq
39-
val x :: Nil = R.unapplySeq(matchh: Any).get
4035
val y :: Nil = R.unapplySeq(matchh).get
41-
bh.consume(x)
4236
bh.consume(y)
4337
}
4438

test/junit/scala/collection/ArrayOpsTest.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,12 @@ class ArrayOpsTest {
3232
val a = Array(1,2,3)
3333
assertEquals(List(3,2,1), a.reverseIterator.toList)
3434
}
35+
36+
@Test
37+
def folds: Unit = {
38+
val a = Array(1,2,3)
39+
assertEquals(6, a.foldLeft(0){ (a, b) => a+b })
40+
assertEquals(6, a.foldRight(0){ (a, b) => a+b })
41+
assertEquals(6, a.fold(0){ (a, b) => a+b })
42+
}
3543
}

0 commit comments

Comments
 (0)