https://github.com/hammerlab/iterators
Enrichment-methods for Scala collections (Iterators, Iterables, Arrays)
https://github.com/hammerlab/iterators
Last synced: 11 months ago
JSON representation
Enrichment-methods for Scala collections (Iterators, Iterables, Arrays)
- Host: GitHub
- URL: https://github.com/hammerlab/iterators
- Owner: hammerlab
- License: apache-2.0
- Created: 2016-11-13T21:33:16.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2018-10-24T13:22:27.000Z (over 7 years ago)
- Last Synced: 2025-04-26T07:35:25.332Z (about 1 year ago)
- Language: Scala
- Homepage:
- Size: 239 KB
- Stars: 6
- Watchers: 8
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# iterators
[](https://travis-ci.org/hammerlab/iterators)
[](https://coveralls.io/github/hammerlab/iterators)
[](https://search.maven.org/search?q=g:org.hammerlab%20AND%20a:iterator_*)
Enrichment-methods for Scala collections (`Iterator`s, `Iterable`s, and `Array`s):
```scala
import hammerlab.iterator._
```
```scala
Iterator(1, 2, 3).nextOption // Some(1)
Iterator(1, 2, 3).buffered.headOption // Some(1)
Array(1, 2, 1, 3).countElems
// Map(1→2, 2→1, 3→1)
List(1, 1, 2, 1, 7, 7, 7).runLengthEncode
// Iterator(1→2, 2→1, 1→1, 7→3)
```
Methods are defined in [`org.hammerlab.iterator`](core/shared/src/main/scala/org/hammerlab/iterator) and made available for convenient importing in [`hammerlab.iterator`](core/shared/src/main/scala/hammerlab/iterator)
## examples
by package:
### [`count`](core/shared/src/main/scala/org/hammerlab/iterator/count)
```scala
Array(1, 2, 1, 3).countElems
// Map(1→2, 2→1, 3→1)
Iterator('a→1, 'b→2, 'a→10, 'c→3).countByKey
// Map('a→2, 'b→1, 'c→1)
```
### [`either`](core/shared/src/main/scala/org/hammerlab/iterator/either)
```scala
def L[T](t: T) = Left(t)
def R[T](t: T) = Right(t)
Iterator(R('a), R('b), L(4)).findLeft
// Some(4)
Iterator(
R('a),
L( 1),
R('b),
R('c),
L( 2),
L( 3),
R('d)
)
.groupByLeft
.mapValues(_.mkString(""))
.toList
// List((1,bc), (2,""), (3,d))
```
### [`end`](core/shared/src/main/scala/org/hammerlab/iterator/end)
`.finish`: run a closure when the iterator is finished traversing:
```scala
import scala.io.Source.fromFile
val source = fromFile("build.sbt")
source
.filter(_ == 'a')
.finish({
println("closing!")
source.close()
})
.size
// 32
// prints "closing!" and closes `source` after traversal is finished
```
`.dropright`: drop `k` elements from the end of an iterator in `O(k)` space:
```scala
Iterator(1 to 10: _*).dropright(4)
// Iterator(1, 2, 3, 4, 5, 6)
```
### [`group`](core/shared/src/main/scala/org/hammerlab/iterator/group)
Group runs of elements that satisfy a predicate or equivalence relation:
```scala
Iterator(1, 0, 2, 3, 0, 0, 4, 5, 6).groupRuns(_ > 0)
// Iterator(Iterator(1), Iterator(0), Iterator(2, 3), Iterator(0), Iterator(0), Iterator(4, 5, 6))
```
Run-length encode elements:
```scala
List(1, 1, 2, 1, 7, 7, 7).runLengthEncode
// Iterator(1→2, 2→1, 1→1, 7→3)
```
Contiguous weighted sums up to a maximum:
```scala
Iterator(1 to 6: _*).cappedCostGroups(costFn = x⇒x, limit = 10)
// Iterator(Iterator(1, 2, 3, 4), Iterator(5), Iterator(6))
```
### [`level`](core/shared/src/main/scala/org/hammerlab/iterator/level)
Flatten a nested iterator but retain access to a cursor into unflattened version:
```scala
val it1 = Iterator(1, 2)
val it2 = Iterator(3, 4)
val it = Iterator(it1, it2).level
it.cur.get == it1
// true
it.next
// 1
it.cur.get == it1
// true
it.next
// 2
it.cur.get == it2
// true
it.next
// 3
it.cur.get == it2
// true
it.next
// 4
it.cur
// None
```
### [`ordered`](core/shared/src/main/scala/org/hammerlab/iterator/ordered)
A variety of merge operations are available for sequences that are mutually ordered (possibly with respect to some 3rd type that each of their elements can be converted to).
#### `.eitherMerge`
Merge two ordered sequences using `Either`s to preserve provenance (or handle the case that the sequences' elements are not the same type):
```scala
Seq(1, 3, 4).eitherMerge(Seq(2, 3, 5, 6))
// Iterator(L(1), R(2), L(3), R(3), L(4), R(5), R(6))
```
#### `.orMerge`
Merge two ordered sequences using `Or`s:
```scala
Seq(1, 3, 4).orMerge(Seq(2, 3, 5, 6))
// Iterator(L(1), R(2), Both(3, 3), L(4), R(5), R(6))
```
#### `.leftMerge`
Collecting right-side elements for each left-side element:
```scala
Seq(1, 3, 4).leftMerge(Seq(2, 3, 5, 6))
// Iterator((1,Iterator(2)), (3,Iterator(3)), (4,Iterator(5, 6)))
```
#### `.merge`
```scala
Seq(1, 3, 4).merge(Seq(2, 3, 5, 6))
// Iterator(1, 2, 3, 3, 4, 5, 6)
```
#### Merging with a 3rd type
Instances of the `View` type-class let merges use a type other than that of the elements being merged:
```scala
// Rank a (Symbol,Int) pair using its Int value
implicit val view = View[(Symbol, Int), Int](_._2)
Seq('a→1, 'b→3).merge('c→2)
// Iterator('a→1, 'c→2, 'b→3)
Seq('a → 1, 'b → 3).eitherMerge(2)
// Iterator(L('a→1), R(2), L('b→3))
```
### [`range`](core/shared/src/main/scala/org/hammerlab/iterator/range)
`sliceOpt`, given a `start` and `length`:
```scala
(0 to 9).sliceOpt(0, 5)
// 0 to 4
(0 to 9).sliceOpt(0, 11)
// 0 to 9
(0 to 9).sliceOpt(2, 10)
// 2 to 9
(0 to 9).sliceOpt(2, 1)
// 2 to 2
```
Also, [`.joinOverlaps`](core/shared/src/main/scala/org/hammerlab/iterator/range/OverlappingRanges.scala) left-merges sequences of [`Range`s](core/shared/src/main/scala/org/hammerlab/iterator/range/Range.scala), sorted by start-coordinate, based on overlaps.
### [`sample`](core/shared/src/main/scala/org/hammerlab/iterator/sample): reservoir-sample
Reservoir-sample:
```scala
Iterator(1 to 100: _*).sample(5)
Array(15, 18, 55, 63, 98)
```
### [`scan`](core/shared/src/main/scala/org/hammerlab/iterator/scan)
- scanL, scanR
- in terms of [`cats.Monoid`](https://typelevel.org/cats/typeclasses/monoid.html)
- optionally include the final (total/sum) element *instead of* the initial empty/zero
```scala
import hammerlab.monoid._ // some Monoid defaults
Seq(1, 2, 3, 4).scanL
// Iterator(0, 1, 3, 6)
Seq(1, 2, 3, 4).scanLeftInclusive
// Iterator(1, 3, 6, 10)
Seq(1, 2, 3, 4).scanR
// Iterator(9, 7, 4, 0)
Seq(1, 2, 3, 4).scanRightInclusive
// Iterator(10, 9, 7, 4)
```
Additionally, scan over values of kv-pairs:
```scala
Seq('a'→1, 'b'→2, 'c'→3, 'd'→4).scanLeftValues
// Iterator((a,0), (b,1), (c,3), (d,6))
Seq('a'→1, 'b'→2, 'c'→3, 'd'→4).scanLeftValuesInclusive
// Iterator((a,1), (b,3), (c,6), (d,10))
Seq('a'→1, 'b'→2, 'c'→3, 'd'→4).scanRightValues
// Iterator((a,9), (b,7), (c,4), (d,0))
Seq('a'→1, 'b'→2, 'c'→3, 'd'→4).scanRightValuesInclusive
// Iterator((a,10), (b,9), (c,7), (d,4))
```
### [`sliding`](core/shared/src/main/scala/org/hammerlab/iterator/sliding)
Windows of size 2, including an optional next or previous element:
```scala
Seq(1, 2, 3).sliding2
// Iterator((1,2), (2,3))
Seq(1, 2, 3).sliding2Opt
// Iterator((1,Some(2)), (2,Some(3)), (3,None))
Seq(1, 2, 3).sliding2Prev
// Iterator((None,1), (Some(1),2), (Some(2),3))
```
Windows of size 3, including 2 succeeding elements, one successor and one predecessor, or full tuples only:
```scala
Seq(1, 2, 3, 4).sliding3
// Iterator((1,2,3), (2,3,4))
Seq(1, 2, 3, 4).sliding3Opt
// Iterator((None,1,Some(2)), (Some(1),2,Some(3)), (Some(2),3,Some(4)), (Some(3),4,None))
Seq(1, 2, 3, 4).sliding3NextOpts
// Iterator((1,Some(2),Some(3)), (2,Some(3),Some(4)), (3,Some(4),None), (4,None,None))
```
Windows of arbitrary size, output having same number of elems as input:
```scala
Seq(1, 2, 3, 4, 5).slide(4)
// Iterator(Seq(1, 2, 3, 4), Seq(2, 3, 4, 5), Seq(3, 4, 5), Seq(4, 5), Seq(5))
```
### [`start`](core/shared/src/main/scala/org/hammerlab/iterator/start)
- `take`s, `drop`s, `collect`s with deterministic semantics around the iterator that was operated on
- `headOption`, `nextOption`