Bronze, Silver, & Gold Challenges: Ch. 22

Bronze Challenge

Generics are probably the most abstract part about Swift so far for me, so it took me a little longer than normal to wrap my head around them. Here’s my filter function for the Bronze challenge:

struct Stack<Element>: Sequence {
    ...
    func filter(_ f: (Element) -> Bool) -> Stack<Element> {
        var filteredItems = Stack<Element>()
        for item in items {
            if f(item) == true {
                filteredItems.push(item)
            }
        }
        return filteredItems
    }
}

var filteredStack = myStack.filter({ $0 == 1 })
for value in filteredStack {
    print("Filtered stack values: \(value)")
}

Silver Challenge

This one is kind-of straightforward. Create the findAll(_:_:) function with the challenge speifications, making sure to make it generic:

func findAll<T: Equatable>(_ array: [T], _ elementToFind: T) -> [Int] {
    var positions = [Int]()
    for (index, item) in array.enumerated() {
        if item == elementToFind {
            positions.append(index)
        }
    }
    return positions
}

findAll([5,3,7,3,9], 3) // returns [1, 3]
findAll(["hey", "what", "thats", "what", "hey"], "hey") // returns [0, 4]

Gold Challenge

This one is really going over my head. I feel like I am so close to the solution for this, however nothing I’m doing is compiling. If anyone has the solution for this, please share!

After three straight days and a Lot of persistence, I finally did it. I don’t know if it’s the best solution, but it’s a solution.
If anyone got a better way to solve this, please post it. Thanks.

func findAll<T>(_ collection: T, _ element: Any) -> [Any] where T: Collection  {
    var locations: [Any] = []


    switch collection {
    
    case is Array<Any>:
    
        for (a,b) in collection.enumerated()  {
        
            if String(describing: b) == String(describing: element) {
                locations.append(a)
            }
        }
    
    case is Dictionary<AnyHashable, Any>:
    
        for (a,b) in collection as! [AnyHashable:Any] {
            if String(describing: b) == String(describing: element) {
                locations.append(a.base)
            }
        }
    
    case is String.CharacterView:
    
        for (a,b) in collection.enumerated() {
            if String(describing: b) == String(describing: element) {
                locations.append(a)
            }
        }

    default:
    
        print("Collection type not applicable")

    }


    return locations

}

findAll([5, 3, 7, 3, 9], 3) // Prints [1,3]

findAll([“a”,“f”,“c”, “a”, “b”, “c”, “c”], “c”) // Returns [2,5,6]

findAll([“c”:1, “b”:2, “f”:3, “a”:0, “g”:2], 2) // Returns [“b”,“g”]

findAll([3:“a”, 1:“b”, 4:“c”, 2:“b”], “c”) // Returns [4]

findAll(“abcdedcba”.characters, “d”) // Returns [3,5]

let set: Set = [“a”, “b”, “c”, “d”]
findAll(set, “c”) // Returns [] and prints “Collection type not applicable”

And here is the gold one :slight_smile:

func findAll<T: Equatable, C: Collection>(_ elements: C, compare: T) -> [C.Index]? where C.Iterator.Element == T  {
    
    var resultArray = Array<C.Index>()
    var index = elements.startIndex
    
    for element in elements {
        if element == compare {
            resultArray.append(index)
        }
        index = elements.index(after: index)
    }
    return resultArray
}

findAll([“asd”, “qowiue”, “asd”], compare: “asd”) // returns [0, 2]

A solution using an extension over Collection and functional programming:

extension Collection where Iterator.Element: Equatable, Indices.Iterator.Element == Index {
    func findAll(_ element: Iterator.Element) -> [Index] {
        return indices.reduce([]) {
            element == self[$1] ? $0 + [$1] : $0
        }
    }
}

BTW, the Indices.Iterator.Element == Index is necessary because of what seems to be a bug or limitation in the Swift compiler.

Hello, guys. Why did I get this sort of issue?

That’s because you’re feeding “print” with an optional. Just provide a default value like this:

print(intStack.pop() ?? 0)

no more warning.

I’m sorry but I have another stupid question. It has to do with IteratorProtocol. In Apple’s documentation it’s explained how iteration work under the hood.
I have the array of animals:
let animals = ["Antelope", "Butterfly", "Camel", "Dolphin"]
Then I called the makeIterator() method.


It is said that makeIterator() returns array over the elements of the collection:
The problem is I don’t understand what is the iterator. I read wikipedia, stackoverflow and other resources but I still can’t understand.

Iterators are objects that enable you to access other objects in containers.

For example, using an iterator you can access the integer values in an array containing integers.

You should really read The Swift Programming Language cover to cover several times, paying special attention to the section Collection Types.

_rom
Yours works fine for sets, arrays , sequences of elements, but
I have yet to find a way to input the search for element parameter
for a Dictionary input.

func findAll<C: Collection>(_ someCollection: C, _ someItem: C.Element) -> [C.Index] where C.Element: Equatable {
var newCollection = C.Index
var index = someCollection.startIndex

for item in someCollection {
    if item == someItem {
        newCollection.append(index)
    }
    index = someCollection.index(after: index)
}
return newCollection

}

Anybody know what

var filteredStack = myStack.filter( { $0 == 1 } ) means?

More specifically the ( { $0 == 1 } ) part?

{ $0 == 1 } is the concise form of the closure expression {(u:Int) -> Bool in return u == 1} passed in to the filter function.

This is explained in the The Swift Programming Language guide’s Closures section.

1 Like

Ok thanks. I’ll have to visit there more frequently