Swift for-in loop with enumerate on custom Array2D class? - swift

How would I go about implementing a custom enumerate function that makes something like this work (Swift 2):
for ((column, row), item) in Array2D.enumerate() { ... }
In my simple Array2D struct:
struct Array2D<T> : SequenceType {
let columns: Int
let rows: Int
private var array: Array<T?>
init(columns: Int, rows: Int) {
self.columns = columns
self.rows = rows
array = Array(count: rows*columns, repeatedValue: nil)
}
subscript(column: Int, row: Int) -> T? {
get {
return array[columns*row + column]
}
set {
array[columns*row + column] = newValue
}
}
func generate() -> AnyGenerator<T?> {
var column = 0
var row = 0
return anyGenerator() {
guard row < self.rows else {
return nil
}
let item = self[column, row]
if ++column == self.columns {
column = 0
++row
}
return item
}
}
}
I couldn't find any good explanation on implementing an enumerate function in Swift

The enumerate() function in Swift returns integers starting from 0 for the first part of its tuple. Those have nothing to do with the sequence you're enumerating over. So, for instance, this won't work:
let word = "hello".characters
for (index, letter) in word.enumerate() {
print(word[index])
}
Because the indices of a characterView are String.Indexs.
So there are several ways to get what you're going for. The first is to just overload enumerate() for your struct. Again, there are a few days you could do this. First off, how about a function that uses your own generator, and uses its own logic to figure out the coordinates. This could work:
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
let g = self.generate()
var coord = -1
return anyGenerator {
g.next().map { ((++coord % self.columns, coord / self.columns), $0) }
}
}
But you're duplicating code there, especially from your generate method. Seeing you're already using coordinates to return each element, why not just have your enumerate method be the default, and your generate method call on that. Something like this:
// Original generate method, now returns the coords it used
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
var column = 0
var row = 0
return anyGenerator() {
guard row < self.rows else {
return nil
}
let item = self[column, row]
if ++column == self.columns {
column = 0
++row
}
return ((column, row), item)
}
}
// uses enumerate, ignores coords
func generate() -> AnyGenerator<T?> {
let g = self.enumerate()
return anyGenerator {
g.next().map { $1 }
}
}
If you wanted to go a little overboard, you could write an enumerate function that enumerates the specific indices of its base. Call it specEnumerate:
public struct SpecEnumerateGen<Base : CollectionType> : GeneratorType {
private var eG: Base.Generator
private let sI: Base.Index
private var i : Base.Index?
public mutating func next() -> (Base.Index, Base.Generator.Element)? {
i?._successorInPlace() ?? {self.i = self.sI}()
return eG.next().map { (i!, $0) }
}
private init(g: Base.Generator, i: Base.Index) {
self.eG = g
self.sI = i
self.i = nil
}
}
public struct SpecEnumerateSeq<Base : CollectionType> : SequenceType {
private let col: Base
public func generate() -> SpecEnumerateGen<Base> {
return SpecEnumerateGen(g: col.generate(), i: col.startIndex)
}
}
public extension CollectionType {
func specEnumerate() -> SpecEnumerateSeq<Self> {
return SpecEnumerateSeq(col: self)
}
}
With this function, this would work:
let word = "hello".characters
for (index, letter) in word.specEnumerate() {
print(word[index])
}
But your matrix struct is still a SequenceType, with no specific indices. For that, you'll have to implement your own MatrixIndex:
public struct MatrixIndex: BidirectionalIndexType {
public let x, y : Int
private let columns: Int
public func successor() -> MatrixIndex {
return (x + 1 == columns) ?
MatrixIndex(x: 0, y: y + 1, columns: columns) :
MatrixIndex(x: x + 1, y: y, columns: columns)
}
public func predecessor() -> MatrixIndex {
return (x == 0) ?
MatrixIndex(x: columns - 1, y: y - 1, columns: columns) :
MatrixIndex(x: x - 1, y: y, columns: columns)
}
}
public func == (lhs: MatrixIndex, rhs: MatrixIndex) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
extension MatrixIndex : CustomDebugStringConvertible {
public var debugDescription: String {
return "\(x), \(y)"
}
}
extension MatrixIndex: RandomAccessIndexType {
public func advancedBy(n: Int) -> MatrixIndex {
let total = (y * columns) + x + n
return MatrixIndex(x: total % columns, y: total / columns, columns: columns)
}
public func distanceTo(other: MatrixIndex) -> Int {
return (other.x - x) + (other.y - y) * columns
}
}
Right. Now you'll need another matrix struct:
public struct Matrix2D<T> : MutableCollectionType {
public var contents: [[T]]
public subscript(index: MatrixIndex) -> T {
get {
return contents[index.y][index.x]
} set {
self.contents[index.y][index.x] = newValue
}
}
public var count: Int { return contents[0].count * contents.count }
public var startIndex: MatrixIndex {
return MatrixIndex(x: 0, y: 0, columns: contents[0].count)
}
public var endIndex: MatrixIndex {
return MatrixIndex(x: 0, y: contents.endIndex, columns: contents[0].count)
}
}
Right. So now, after all of that, this works:
let myMatrix = Matrix2D(contents: [[1, 2], [3, 4]])
for (coordinate, value) in myMatrix.specEnumerate() {
value == myMatrix[coordinate] // True every time
}

It might suffice defining your own enumerate taking advantage of the one you already have:
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
var index = 0
var g = array.generate()
return anyGenerator() {
if let item = g.next() {
let column = index % self.columns
let row = index / self.columns
++index
return ((column, row) , item)
}
return nil
}
}
Notice in this case you could avoid conforming to SequenceType since I use generate from the private array. Anyway it could be consistent to do so.
Here is how then you could use it:
var a2d = Array2D<Int>(columns: 2, rows: 4)
a2d[0,1] = 4
for ((column, row), item) in a2d.enumerate() {
print ("[\(column) : \(row)] = \(item)")
}
Hope this helps

Related

Swift how to make a set with multiplicity (multiset)

I am substracting two Array of Integers. I did the substraction using sets :
let numbersA = [1, 2, 3]
let numbersB = [3, 4, 5]
Set(numbersA).subtracting(numbersB)
but I then realized that I have multiplicity in my arrays, and I should take it into account. What is the data structure for multisets in Swift?
In swift 5, there is no Multiset implementation in the core library.
You can reproduce the Multiset behavior by using a dictionary [Element:Multiplicity].
Your code will be:
let numbersA = [1, 2, 3, 3]
let numbersB = [3, 4, 5]
Set(numbersA).subtracting(numbersB) // [1, 2, 3]
As pointed out by Leo Dabus in comment, this gives you an unordered collection as a result.
You can find a good tutorial on multisets at https://github.com/raywenderlich/swift-algorithm-club/tree/master/Multiset
Here is a ready to use implementation of multiset. I added to it the substracting implementation. Notice it can be considered an incomplet implementation of a Multiset since, for exemple, it doesn't extends the Collection protocol.
//
// Multiset.swift
// Multiset
//
// Created by Simon Whitaker on 28/08/2017.
//
// Extended by Jeremy Cochoy on 17/11/2019
import Foundation
public struct Multiset<T: Hashable> {
private var storage: [T: UInt] = [:]
public private(set) var count: UInt = 0
public init() {}
public init<C: Collection>(_ collection: C) where C.Element == T {
for element in collection {
self.add(element)
}
}
public mutating func add (_ elem: T) {
storage[elem, default: 0] += 1
count += 1
}
public mutating func remove (_ elem: T) {
if let currentCount = storage[elem] {
if currentCount > 1 {
storage[elem] = currentCount - 1
} else {
storage.removeValue(forKey: elem)
}
count -= 1
}
}
public func isSubSet (of superset: Multiset<T>) -> Bool {
for (key, count) in storage {
let supersetcount = superset.storage[key] ?? 0
if count > supersetcount {
return false
}
}
return true
}
public func count(for key: T) -> UInt {
return storage[key] ?? 0
}
public var allItems: [T] {
var result = [T]()
for (key, count) in storage {
for _ in 0 ..< count {
result.append(key)
}
}
return result
}
public func subtracting(_ elems: [T]) -> Multiset<T> {
var resultSet = self
elems.forEach { resultSet.remove($0) }
return resultSet
}
}
// MARK: - Equatable
extension Multiset: Equatable {
public static func == (lhs: Multiset<T>, rhs: Multiset<T>) -> Bool {
if lhs.storage.count != rhs.storage.count {
return false
}
for (lkey, lcount) in lhs.storage {
let rcount = rhs.storage[lkey] ?? 0
if lcount != rcount {
return false
}
}
return true
}
}
// MARK: - ExpressibleByArrayLiteral
extension Multiset: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: T...) {
self.init(elements)
}
}
As you say, swift does not have Multiset as a native type.
I implemented a fairly thorough implementation of Multiset in Swift here:
https://github.com/Cortado-J/Multiset
and full documentation of that library with usage examples here:
https://cortado-j.github.io/Multiset/Structs/Multiset.html

Swift: error: cannot use mutating member on immutable value

I'm getting the above error in the following code. The Heap struct is from the Swift Algorithm Club. I'm using the Heap to solve a Hackerrank challenge: Heaps: Find the Running Median.
import Foundation
// Enter your code here
struct Heap<Element> {
var elements : [Element]
let priorityFunction : (Element, Element) -> Bool
init(elements: [Element] = [], priorityFunction: #escaping (Element, Element) -> Bool) {
self.elements = elements
self.priorityFunction = priorityFunction
buildHeap()
}
mutating func buildHeap() {
for index in (0 ..< count / 2).reversed() {
siftDown(elementAtIndex: index)
}
}
var isEmpty : Bool {
return elements.isEmpty
}
var count : Int {
return elements.count
}
func peek() -> Element? {
return elements.first
}
func isRoot(_ index: Int) -> Bool {
return (index == 0)
}
func leftChildIndex(of index: Int) -> Int {
return (2 * index) + 1
}
func rightChildIndex(of index: Int) -> Int {
return (2 * index) + 2
}
func parentIndex(of index: Int) -> Int {
return (index - 1) / 2
}
func isHigherPriority(at firstIndex: Int, than secondIndex: Int) -> Bool {
return priorityFunction(elements[firstIndex], elements[secondIndex])
}
func highestPriorityIndex(of parentIndex: Int, and childIndex: Int) -> Int {
guard childIndex < count && isHigherPriority(at: childIndex, than: parentIndex)
else { return parentIndex }
return childIndex
}
func highestPriorityIndex(for parent: Int) -> Int {
return highestPriorityIndex(of: highestPriorityIndex(of: parent, and: leftChildIndex(of: parent)), and: rightChildIndex(of: parent))
}
mutating func swapElement(at firstIndex: Int, with secondIndex: Int) {
guard firstIndex != secondIndex
else { return }
elements.swapAt(firstIndex, secondIndex)
}
mutating func enqueue(_ element: Element) {
elements.append(element)
siftUp(elementAtIndex: count - 1)
}
mutating func siftUp(elementAtIndex index: Int) {
let parent = parentIndex(of: index)
guard !isRoot(index),
isHigherPriority(at: index, than: parent)
else { return }
swapElement(at: index, with: parent)
siftUp(elementAtIndex: parent)
}
mutating func dequeue() -> Element? {
guard !isEmpty // 1
else { return nil }
swapElement(at: 0, with: count - 1) // 2
let element = elements.removeLast() // 3
if !isEmpty { // 4
siftDown(elementAtIndex: 0) // 5
}
return element // 6
}
mutating func siftDown(elementAtIndex index: Int) {
let childIndex = highestPriorityIndex(for: index) // 1
if index == childIndex { // 2
return
}
swapElement(at: index, with: childIndex) // 3
siftDown(elementAtIndex: childIndex)
}
}
var topHeap = Heap<Int>(priorityFunction: >)
var bottomHeap = Heap<Int>(priorityFunction: <)
let n = Int(readLine(strippingNewline: true)!)!
let val1 = Int(readLine(strippingNewline: true)!)!
print(String(format: "%.1f", Float(val1)))
if n > 1 {
let val2 = Int(readLine(strippingNewline: true)!)!
print(String(format: "%.1f", (Float(val1) + Float(val2)) / 2.0))
if val1 < val2 {
topHeap.enqueue(val1);
bottomHeap.enqueue(val2);
} else {
topHeap.enqueue(val2);
bottomHeap.enqueue(val1);
}
for _ in 2..<n {
let val = Int(readLine(strippingNewline: true)!)!
// Put in the proper heap
if val < topHeap.peek()! {
topHeap.enqueue(val)
} else if val > bottomHeap.peek()! {
bottomHeap.enqueue(val)
} else if topHeap.count < bottomHeap.count {
topHeap.enqueue(val)
} else {
bottomHeap.enqueue(val)
}
// If one heap has two more than the other, move one value
if topHeap.count == bottomHeap.count + 2 {
var element: Int = bottomHeap.dequeue
error: cannot use mutating member on immutable value: 'bottomHeap' is immutable
topHeap.enqueue(element)
} else if bottomHeap.count == topHeap.count + 2 {
bottomHeap.enqueue(topHeap.dequeue)
error: cannot use mutating member on immutable value: 'topHeap' is immutable
}
// If one heap has one more than the other, the top node of the larger heap holds the median
if topHeap.count == bottomHeap.count + 1 {
print(String(format: "%.1f", Float(topHeap.peek()!)))
} else if bottomHeap.count == topHeap.count + 1 {
print(String(format: "%.1f", Float(bottomHeap.peek()!)))
} else {
print(String(format: "%.1f", (Float(topHeap.peek()!) + Float(bottomHeap.peek()!)) / 2.0))
}
}
}
dequeue is a function. You need to add () to the calls.
Then you need to deal with the fact that dequeue() returns an optional Int.

Swift binary tree list of nodes at given depth

I'm writing a Swift algorithm for a binary tree. My goal is to create a list of nodes at specific depth something like
func listNodeAt(_n: Int) --> [T] {
}
Here is my tree class
public class BinaryTreeNode<T:Comparable> {
//Value and children vars
public var value:T
public var leftChild:BinaryTreeNode?
public var rightChild:BinaryTreeNode?
public weak var parent:BinaryTreeNode?
//Initialization
public convenience init(value: T) {
self.init(value: value, left: nil, right: nil, parent:nil)
}
public init(value:T, left:BinaryTreeNode?, right:BinaryTreeNode?, parent:BinaryTreeNode?) {
self.value = value
self.leftChild = left
self.rightChild = right
self.parent = parent
}
}
I have build a helper function to calculate the depth of a Node
//Depth
public func depth() -> Int {
guard var node = parent else {
return 0
}
var depth = 1
while let parent = node.parent {
depth = depth + 1
node = parent
}
return depth
}
How can we achieve the desired function?
func listNodeAt(_ n: Int) -> [T] {
return getElementsAt(n, node: self)
}
private func getElementsAt(_ n: Int, node: BinaryTreeNode<T>, traversingDepth: Int = 0) -> [T] {
var array = Array<T>()
if traversingDepth < n {
if let left = node.leftChild {
array = array + getElementsAt(n, node: left, traversingDepth: traversingDepth + 1)
}
if let right = node.rightChild {
array = array + getElementsAt(n, node: right, traversingDepth: traversingDepth + 1)
}
} else if traversingDepth == n {
array.append(node.value)
}
return array
}
This is one of the solution. Assuming here the self is the root node.

Proper implementation of Sequence Protocol in a Class

I have been working on learning something about the Accelerate framework and am writing a Vector class to go along with my learning experience. I decided I needed to implement the Sequence protocol and after several false starts and much searching for relevant information to my problem finally came up with a solution that seems to work. Not sure if my solution is proper or not and would like comment if there are better ways to do this. Current code is a bit long but not super long so I will post it here.
import Foundation
import Accelerate
public class Vdsp{
public class VectorD: Sequence, IteratorProtocol {
var vindex = 0
public func makeIterator() -> Double? {
return next()
}
public func next() -> Double? {
let nextIndex = self.vindex * self.s + self.o
guard self.vindex < self.l && nextIndex < self.count
else {
self.vindex = 0
return nil
}
self.vindex += 1
return self.data[nextIndex]
}
public let count : Int
fileprivate var l: Int
fileprivate var o: Int
fileprivate var s: Int
public var length : Int {
get {
return self.l
}
set (value){
let l = (value - 1) * self.s + self.o
if l < 0 || l >= self.count {
preconditionFailure("length exceeds vector boundary")
}
self.l = value
}
}
public var stride : Int {
get {
return self.s
}
set (value){
let l = (self.l - 1) * value + self.o
if l < 0 || l >= self.count {
preconditionFailure("stride will cause vector to exceed vector boundary")
}
self.s = value
}
}
public var offset : Int {
get {
return self.o
}
set (value){
let l = (self.l - 1) * self.s + value
if l < 0 || l >= self.count {
preconditionFailure("stride will cause vector to exceed vector boundary")
}
self.o = value
}
}
// length * stride + offset >= 0 and <= count
public var data : Array<Double>
public init(length: Int){
self.count = length
self.l = length
self.s = 1
self.o = 0
data = Array(repeating: 0.0, count: count)
}
// MARK: - Utility functions
public var empty : VectorD { // Create a new vector unit stride, zero offset
get{
return VectorD(length: length)
}
}
public func display(decimals: Int) -> String {
let fmt = String("%0." + String(decimals) + "f\n")
var aString = ""
for i in 0..<length {
aString += String(format: fmt!, self.data[offset + i * stride])
}
return aString
}
// MARK: - Subscripts and Operators
public subscript(index: Int) -> Double {
get {
if index > length {
preconditionFailure("index \(index) out of bounds")
} else {
return data[self.offset + index * self.stride]
}
}
set(newValue) {
if index > self.length {
preconditionFailure("index \(index) out of bounds")
} else {
self.data[self.offset + index * self.stride] = newValue
}
}
}
public static func + (left: VectorD, right: VectorD) -> VectorD {
return Vdsp.add(left, right)
}
public static func + (left: Double, right: VectorD) -> VectorD {
return Vdsp.add(left, right)
}
public static func + (left: VectorD, right: Double) -> VectorD {
return Vdsp.add(right, left)
}
public static func * (left: VectorD, right: VectorD) -> VectorD {
return Vdsp.mul(left, right)
}
public static func * (left: Double, right: VectorD) -> VectorD {
return Vdsp.mul(left, right)
}
public static func * (left: VectorD, right: Double) -> VectorD {
return Vdsp.mul(right, left)
}
// MARK: - vDSP routines as methods of VectorD
public func fill(value: Double){
var v = value
vDSP_vfillD(&v, &data + offset, stride, vDSP_Length(length))
}
public func ramp(start: Double, increment: Double){
var s = start
var i = increment
vDSP_vrampD(&s, &i, &data + offset, stride, vDSP_Length(length))
}
public var sumval : Double {
get {
var s : Double = 0.0
vDSP_sveD(&data + offset, stride, &s, vDSP_Length(length))
return s
}
}
}
// MARK: - vDSP routines as class functions of Vdsp
public static func add(_ v1: VectorD, _ v2: VectorD) -> VectorD {
let v3 = v1.empty
vDSP_vaddD( &v1.data + v1.offset, v1.stride, &v2.data + v2.offset , v2.stride, &v3.data, 1, vDSP_Length(v3.length))
return v3
}
public static func add(_ s: Double, _ v: VectorD) -> VectorD {
var sdta = s
let r = v.empty
vDSP_vsaddD( &v.data + v.offset, v.stride, &sdta, &r.data, 1, vDSP_Length(v.length))
return r
}
public static func mul(_ v1: VectorD, _ v2: VectorD) -> VectorD {
let v3 = v1.empty
vDSP_vmulD( &v1.data + v1.offset, v1.stride, &v2.data + v2.offset, v2.stride, &v3.data, 1, vDSP_Length(v3.length))
return v3
}
public static func mul(_ s: Double, _ v: VectorD) -> VectorD {
var sdta = s
let r = v.empty
vDSP_vsmulD( &v.data + v.offset, v.stride, &sdta, &r.data, 1, vDSP_Length(v.length))
return r
}
}
I am exercising this with
//: Playground for Accelerate
import UIKit
let V = Vdsp.VectorD(length: 10);V.ramp(start: 0.1, increment: 0.2)
print("Vector V after ramp(0.1,0.2)");print(V.display(decimals: 3))
V.length = 4
V.stride = 2
V.offset = 1
print("Vector V after attribute modification")
print(V.display(decimals: 3))
let Q = V.empty
Q.ramp(start: 1.0, increment: 1.0)
print("Vector Q after ramp(1.0,1.0)");print(Q.display(decimals: 3))
print("V * Q"); var R = V * Q
for i in 0..<V.length {
print("\(V[i]) * \(Q[i]) = \(R[i])")
}
R = V + Q; print("V + Q = R")
for i in 0..<V.length {
print("\(V[i]) + \(Q[i]) = \(R[i])")
}
print("\n")
for item in V.data {
print(item)
}
print("\n")
for item in V {
print(item)
}
print("\n")
V.offset = 3
for item in V {
print(item)
}
and I seem to get the proper output. The Sequence protocol is in the first few lines of the VectorD class.
Your implementation of the Sequence protocol is not correct.
First, your makeIterator() method is not used at all because it has the wrong signature,
it does not return an Iterator. (You can remove that function from your code without changing anything.) Iterating over the vector elements works
because there is a default implementation of makeIterator() for all
iterators which are declared to conform to Sequence.
Second, your next() method uses an instance variable vindex
which is reset to zero after reaching the end of the iteration.
In other words, it is assumed that all elements are retrieved before
iterating the same vector again. This gives the unexpected output:
let V = Vdsp.VectorD(length: 10)
V.ramp(start: 1.0, increment: 1.0)
print(Array(V.prefix(4))) // [1.0, 2.0, 3.0, 4.0]
print(Array(V.prefix(4))) // [5.0, 6.0, 7.0, 8.0]
print(Array(V.prefix(4))) // [9.0, 10.0]
print(Array(V.prefix(4))) // [1.0, 2.0, 3.0, 4.0]
Here is a possible implementation of the Sequence protocol:
public class VectorD: Sequence {
public func makeIterator() -> AnyIterator<Double> {
var vindex = 0
return AnyIterator {
let nextIndex = vindex * self.s + self.o
guard vindex < self.l && nextIndex < self.count else {
return nil
}
vindex += 1
return self.data[nextIndex]
}
}
// ...
}
Note that vindex is now a local variable of makeIterator()
and captured by the closure. Calling makeIterator() again
will start from the beginning even if the previous iteration did
not retrieve all elements:
print(Array(V.prefix(4))) // [1.0, 2.0, 3.0, 4.0]
print(Array(V.prefix(4))) // [1.0, 2.0, 3.0, 4.0]
Another possible implementation would be
public class VectorD: Sequence {
public func makeIterator() -> AnyIterator<Double> {
let upperBound = Swift.min(count, o + l * s)
let it = Swift.stride(from: o, to: upperBound, by: s)
.lazy.map { self.data[$0] }.makeIterator()
return AnyIterator(it)
}
// ...
}
using the stride() method from the Swift standard
library.

Conforming a new protocol to Sequence with a default makeIterator() implementation

I made a (very basic) BinaryTree protocol:
public enum BinaryTreeChildSide {
case left, right
}
public protocol BinaryTree {
associatedtype Element
associatedtype Index
func child(of index: Index, side: BinaryTreeChildSide) -> Index?
var rootIndex: Index? { get }
subscript(position: Index) -> Element { get }
}
For a basic iterative in-order traversal, I made a BinaryTreeIterator (note that I don't implement Sequence just yet):
public extension BinaryTree {
func makeIterator() -> BinaryTreeIterator<Self> {
return BinaryTreeIterator(self)
}
}
public struct BinaryTreeIterator<Tree: BinaryTree>: IteratorProtocol {
private let tree: Tree
private var stack: [Tree.Index]
private var index: Tree.Index?
private init(_ tree: Tree) {
self.tree = tree
stack = []
index = tree.rootIndex
}
public mutating func next() -> Tree.Element? {
while let theIndex = index {
stack.append(theIndex)
index = tree.child(of: theIndex, side: .left)
}
guard let currentIndex = stack.popLast() else { return nil }
defer { index = tree.child(of: currentIndex, side: .right) }
return tree[currentIndex]
}
}
Implementing a binary heap to this protocol is also pretty straight-forward:
public struct BinaryHeap<Element> {
private var elements: [Element]
public init(_ elements: [Element]) {
self.elements = elements
}
}
extension BinaryHeap: BinaryTree {
private func safeIndexOrNil(_ index: Int) -> Int? {
return elements.indices.contains(index) ? index : nil
}
public func child(of index: Int, side: BinaryTreeChildSide) -> Int? {
switch side {
case .left: return safeIndexOrNil(index * 2 + 1)
case .right: return safeIndexOrNil(index * 2 + 2)
}
}
public var rootIndex: Int? { return safeIndexOrNil(0) }
public subscript(position: Int) -> Element {
return elements[position]
}
}
So far, so good. I can now make a simple heap and iterate through its elements:
let heap = BinaryHeap([4, 2, 6, 1, 3, 5, 7])
var iterator = heap.makeIterator()
while let next = iterator.next() {
print(next, terminator: " ")
}
// 1 2 3 4 5 6 7
This works, but of course the goal of implementing makeIterator() is to conform to Sequence. however, if I replace
public protocol BinaryTree {
with
public protocol BinaryTree: Sequence {
then the compiler complains that BinaryHeap doesn't implement Sequence because the associated type Iterator couldn't be inferred. If I manually specify the Iterator type with
extension BinaryHeap: BinaryTree {
typealias Iterator = BinaryTreeIterator<BinaryHeap>
...
}
then the compiler shows an error that Iterator circularly references itself. So that might be why the Iterator type couldn't be inferred.
Interestingly, it works if I wrap my custom BinaryTreeIterator in an AnyIterator instance:
public extension BinaryTree {
func makeIterator() -> AnyIterator<Element> {
return AnyIterator(BinaryTreeIterator(self))
}
}
let heap = BinaryHeap([4, 2, 6, 1, 3, 5, 7])
for number in heap {
print(number, terminator: " ")
}
// 1 2 3 4 5 6 7
Apple's own IndexingIterator seems to work in a similar fashion to my BinaryTreeIterator:
public struct IndexingIterator<
Elements : IndexableBase
// FIXME(compiler limitation):
// Elements : Collection
> : IteratorProtocol, Sequence {
...
}
From the source code. Maybe the problem I'm facing might also be because of the compiler limitation mentioned there, but I don't know for sure.
Is there a way to conform BinaryTree to Sequence without using AnyIterator?
This is the farthest I could take it. Now the compiler will still complain about the heap not containing any makeIterator member
(which I thought was included by default once someone conforms to sequence—wrong turns out one must conform to Sequence ​and​ IteratorProtocol for the default implementation) and having a next—but once you add those methods its smooth sailing.
So makeIterator + next method to make Mr/Mrs/Preferred Gender Pronoun compiler happy.
public enum BinaryTreeChildSide {
case left, right
}
public struct BinaryTreeIterator<Tree: BinaryTree>: Sequence, IteratorProtocol {
private let tree: Tree
private var stack: [Tree.Index]
private var index: Tree.Index?
private init(_ tree: Tree) {
self.tree = tree
stack = []
index = tree.rootIndex
}
public mutating func next() -> Tree.Element? {
while let theIndex = index {
stack.append(theIndex)
index = tree.child(of: theIndex, side: .left)
}
guard let currentIndex = stack.popLast() else { return nil }
defer { index = tree.child(of: currentIndex, side: .right) }
return tree[currentIndex]
}
}
public protocol BinaryTree: Sequence {
associatedtype Element
associatedtype Index
func child(of index: Index, side: BinaryTreeChildSide) -> Index?
var rootIndex: Index? { get }
subscript(position: Index) -> Element { get }
}
extension BinaryTree {
func makeIterator() -> BinaryTreeIterator<Self> {
return BinaryTreeIterator(self)
}
}
extension BinaryHeap {
private func safeIndexOrNil(_ index: Int) -> Int? {
return elements.indices.contains(index) ? index : nil
}
public func child(of index: Int, side: BinaryTreeChildSide) -> Int? {
switch side {
case .left: return safeIndexOrNil(index * 2 + 1)
case .right: return safeIndexOrNil(index * 2 + 2)
}
}
public var rootIndex: Int? { return safeIndexOrNil(0) }
public subscript(position: Int) -> Element {
return elements[position]
}
}
public struct BinaryHeap<Element> {
private var elements: [Element]
public init(_ elements: [Element]) {
self.elements = elements
}
}
let heap = BinaryHeap([4, 2, 6, 1, 3, 5, 7])
var iterator = heap.makeIterator()
while let next = iterator.next() {
print(next, terminator: " ")
}
Apparently it was a Swift bug: my code compiles fine using Swift 3.1.