Latest  1.1.0 

Homepage  https://github.com/mpangburn/IteratorTools 
License  MIT 
Platforms  ios 8.0 
Authors 
A Swift port of Python’s itertools.
The [framework] standardizes a core set of fast, memory efficient tools that are useful by themselves or in combination. Together, they form an “iterator algebra” making it possible to construct specialized tools succinctly and efficiently in pure [Swift].
Table of Contents
 From Python to Swift
 Infinite IteratorSequences
 Installation
 Documentation
 License
From Python to Swift
Python’s iterator
and iterable
protocols are equivalent to Swift’s IteratorProtocol
and Sequence
. In Python, every iterator
must also be an iterable
. Though Swift has no such constraint, the return types of IteratorTools functions implement both IteratorProtocol
and Sequence
(or, in certain cases, LazySequenceProtocol
) to follow Python’s pattern and to reduce boilerplate code. These types will henceforth be referred to as iteratorsequences.
Due to the current limitations of generics in Swift’s typing system, some functions cannot be generalized to the extent to which they are in Python. These limitations are noted where appropriate in the documentation below.
Free Functions and Methods
While Python favors free functions, Swift favors methods. Where applicable, methods are implemented eagerly as Sequence extensions (returning arrays) and lazily as LazySequenceProtocol extensions (returning iteratorsequences). For example:
let values = [1, 2, 3].cycle(times: 2)
// [1, 2, 3, 1, 2, 3]
let values = [1, 2, 3].lazy.cycle(times: 2)
// 1, 2, 3, 1, 2, 3
Functions such as product
, however, are better semantically suited as free functions. The free functions in IteratorTools always compute lazily, though they can be casted to an array to access all values eagerly.
let values = product([1, 2, 3], [4, 5, 6])
// [1, 4], [1, 5], [1, 6], [2, 4], [2, 5], ...
let values = Array(product([1, 2, 3], [4, 5, 6]))
// [[1, 4], [1, 5], [1, 6], [2, 4], [2, 5], ... ]
The table below lists the functions provided by Python’s itertools and their Swift counterparts.
itertools  Free Function(s)  Method(s)  Notes 

accumulate 
accumulate(_:) 

chain 
chain(_:) 

chain.from_iterable 
chain(_:) 

combinations , combinations_with_replacement 
combinations(length:repeatingElements:) 

compress 
compress(data:selectors:) 

count 
counter() , counter(start:step:) 

cycle 
cycle() , cycle(times:) 

dropwhile 
drop(while:) 
Provided by Swift standard library  
filterfalse 
reject(predicate:) 
Renamed for clarity  
groupby 
grouped(by:) 

islice 
stride(from:to:by:) 
Provided by Swift standard library  
permutations 
permutations(repeatingElements:) , permutations(length:repeatingElements:) 

product 
product(_:) , product(_:repeated:_ , mixedProduct(_:_:) 
See distinctions below  
repeat 
repeater(value:) , repeater(value:times:) 
repeat keyword taken in Swift 

starmap 
No appropriate Swift equivalent  
takewhile 
prefix(while:) 
Provided by Swift standard library  
tee 
tee(_:) 

zip_longest 
zipToLongest(_:_:firstFillValue:secondFillValue:) 
Infinite IteratorSequences
The iteratorsequences returned by counter(start:step:)
, repeater(value:)
, and cycle()
are infinite. These iteratorsequences adopt LazySequenceProtocol, so operations such as map
and filter
are implemented lazily. As a result, they can be used even though the sequences are infinite. In practice, iterating over an infinite iteratorsequence requires a statement such as break
or return
to transfer the flow of control out of the otherwise infinite loop.
The iteratorsequences returned by repeater(value:times:)
and the lazy version of cycle(times:)
, though finite, are of the same types as those produced by their infinite counterparts.
Installation
CocoaPods
To install via CocoaPods, add the following line to your Podfile:
pod "IteratorTools"
Carthage
To install via Carthage, add the following line to your Cartfile:
github "mpangburn/IteratorTools"
Documentation
Free Functions
chain(_:)
Returns an iteratorsequence that returns values from each sequence until all are exhausted. This function is used for treating consecutive sequences as a single sequence. chain(_:)
is overloaded to accept either any number of sequences or an array of sequences as parameters.
let values = chain([1, 2, 3], [4, 5, 6])
// 1, 2, 3, 4, 5, 6
let values = chain([[1, 2, 3], [4, 5, 6]])
// 1, 2, 3, 4, 5, 6
compress(data:selectors:)
Returns an iteratorsequence that filters elements from data
, returning only those that have a corresponding true
in selectors
. Iteration stops when either data
or selectors
has been exhausted.
let values = compress(data: [1, 2, 3, 4], selectors: [true, true, false, true])
// 1, 2, 4
let values = compress(data: [1, 2, 3], selectors: [true, false, true, true, true])
// 1, 3
counter(start:step:)
Returns an infinite iteratorsequence beginning at start
and incrementing by step
. By default, this function creates a counter beginning at zero and incrementing by one.
let values = counter()
// 0, 1, 2, 3, 4, ...
let values = counter(start: 1, step: 2)
// 1, 3, 5, 7, 9, ...
product(_:)
, product(_:repeated:)
, mixedProduct(_:_:)
The product
functions return iteratorsequences for the Cartesian product of sequences. For sequences containing elements of the same type, product
works as its Python counterpart in that the product can be generated from any number of sequences. To avoid compiletime ambiguity, the function for taking the product of sequences of different types has been renamed mixedProduct
. Due to Swift’s strong, static typing system, mixedProduct
can take only a finite number of arguments. In the future, mixedProduct
may be overloaded to take more than two arguments, but each of these implementations must be done individually.
product(_:)
Returns an iteratorsequence for the Cartesian product of the sequences.
let values = product([1, 2, 3], [4, 5, 6, 7], [8, 9])
// [1, 4, 8], [1, 4, 9], [1, 5, 8], [1, 5, 9], [1, 6, 8], ... [3, 7, 9]
product(_:repeated:)
Returns an iteratorsequence for the Cartesian product of the sequence repeated with itself a number of times.
let values = product([1, 2, 3], repeated: 2)
// Equivalent to product([1, 2, 3], [1, 2, 3])
mixedProduct(_:_:)
Returns an iteratorsequence for the Cartesian product of two sequences containing elements of different types.
let values = mixedProduct(["a", "b"], [1, 2, 3])
// ("a", 1), ("a", 2), ("a", 3), ("b", 1), ("b", 2), ("b", 3)
repeater(value:times:)
Returns an iteratorsequence repeating a value, either infinitely or a specified number of times. This function defaults to infinite repetition without an argument for times
.
let values = repeater(value: 0)
// 0, 0, 0, 0, ...
let values = repeater(value: 0, times: 3)
// 0, 0, 0
zipToLongest(_:_:firstFillValue:secondFillValue:)
Returns an iteratorsequence that aggregates elements from each of the sequences. If the sequences are of uneven length, missing values are filledin with the corresponding fill value. Iteration continues until the longest sequence is exhausted. Because of limitations with Swift’s generics, zipToLongest
can take only a finite number of arguments. In the future, zipToLongest
may be overloaded to take more than two arguments, but each of these implementations must be done individually at this point in time.
let values = zipToLongest([1, 2], ["a", "b", "c"], firstFillValue: 0, secondFillValue: "z"
// (1, "a"), (2, "b"), (0, "c")
let values = zipToLongest([1, 2, 3, 4], ["a", "b"], firstFillValue: 0, secondFillValue: "z")
// (1, "a"), (2, "b"), (3, "z"), (4, "z")
Methods
accumulate(_:)
Returns an array (eager) or an iteratorsequence (lazy) of consecutively accumulated values from the sequence using the specified function.
let values = [1, 2, 3, 4].accumulate(+)
// [1, 3, 6, 10]
let values = [1, 2, 3, 4].lazy.accumulate(+)
// 1, 3, 6, 10
combinations(length:repeatingElements)
Returns an array (eager) or an iteratorsequence (lazy) of the combinations of the specified length of elements in the sequence.
let values = [1, 2, 3, 4].combinations(length: 2, repeatingElements: false)
// [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
let values = [1, 2, 3, 4].combinations(length: 2, repeatingElements: true)
// [[1, 1], [1, 2], [1, 3], [1, 4], [2, 2], [2, 3], [2, 4], [3, 3], [3, 4]]
let values = [1, 2, 3, 4].lazy.combinations(length: 2, repeatingElements: false)
// [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]
let values = [1, 2, 3, 4].lazy.combinations(length: 2, repeatingElements: true)
// [1, 1], [1, 2], [1, 3], [1, 4], [2, 2], [2, 3], [2, 4], [3, 3], [3, 4]
cycle(), cycle(times:)
cycle()
Returns an iteratorsequence cycling infinitely through the sequence. This function always computes lazily.
let values = [1, 2, 3].cycle()
// 1, 2, 3, 1, 2, 3, 1, ...
cycle(times:)
Returns an array (eager) or an iteratorsequence (lazy) of times
cycles of self.
let values = [1, 2, 3].cycle(times: 2)
// [1, 2, 3, 1, 2, 3]
let values = [1, 2, 3].lazy.cycle(times: 2)
// 1, 2, 3, 1, 2, 3
grouped(by:)
Returns an array (eager) or an iteratorsequence (lazy) of consecutive keys and groups from the sequence as tuples.
Groups are made based on the element’s output from the given key function.
A group is cut as soon as the sequence’s next value produces a different key.
Generally, the sequence should be sorted on the same key function to group all values with the same key.
let values = (0...10).sorted(by: { $0 % 3 < $1 % 3 }).grouped(by: { $0 % 3 })
// [(key: 0, elements: [0, 3, 6, 9]), (key: 1, elements: [1, 4, 7, 10]), (key: 2, elements: [2, 5, 8])]
let values = (0...10).sorted(by: { $0 % 3 < $1 % 3 }).lazy.grouped(by: { $0 % 3 })
// (key: 0, elements: [0, 3, 6, 9]), (key: 1, elements: [1, 4, 7, 10]), (key: 2, elements: [2, 5, 8])
permutations(length:repeatingElements:)
Returns an array (eager) or an iteratorsequence (lazy) containing the permutations of elements in the sequence, optionally of a specified length. If no length
argument is provided, the permutation length defaults to the length of the sequence.
let values = [1, 2, 3].permutations(repeatingElements: false)
// [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
let values = [1, 2, 3].permutations(length: 2, repeatingElements: true)
// [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]
let values = [1, 2, 3].lazy.permutations(repeatingElements: false)
// [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
let values = [1, 2, 3].lazy.permutations(length: 2, repeatingElements: true)
// [1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]
reject(predicate:)
Returns an array (eager) or an iteratorsequence (lazy) containing only the elements from the sequence for which the predicate is false.
let values = [1, 2, 3, 4, 5].reject { $0 % 2 == 0 }
// [1, 3, 5]
let values = [1, 2, 3, 4, 5].lazy.reject { $0 % 2 == 0 }
// 1, 3, 5
tee(_:)
Returns an array (eager) or an iteratorsequence (lazy) of the specified number of independent iterators from the sequence. If no argument is provided, the function defaults to producing two independent iterators.
let iterators = [1, 2, 3].tee()
// an array of two independent iterators of [1, 2, 3]
let iterators = [1, 2, 3].tee(3)
// an array of three independent iterators of [1, 2, 3]
let iterators = [1, 2, 3].lazy.tee()
// an iteratorsequence of two independent iterators of [1, 2, 3]
let iterators = [1, 2, 3].lazy.tee(3)
// an iteratorsequence of three independent iterators of [1, 2, 3]
License
IteratorTools is released under the MIT license. See LICENSE for details.
Latest podspec
{ "name": "IteratorTools", "version": "1.1.0", "summary": "A Swift port of Python's itertools.", "description": "A Swift port of Python's itertools. Contains utility functions utilizing IteratorProtocol, Sequence, and LazySequenceProtocol.", "homepage": "https://github.com/mpangburn/IteratorTools", "license": { "type": "MIT", "file": "LICENSE" }, "authors": { "mpangburn": "[email protected]" }, "source": { "git": "https://github.com/mpangburn/IteratorTools.git", "tag": "1.1.0" }, "platforms": { "ios": "8.0" }, "source_files": "Sources/**/*", "pushed_with_swift_version": "4.0" }
Tue, 12 Dec 2017 18:40:28 +0000