Stuck on the Bronze Challenge

I’ve been struggling with this one…

I modeled it after func map from Listing 21.8, but it won’t compile. I looked back at Closure documentation but that didn’t help either.

So I’m stuck.

func filter<Element>(_ element: (Element) -> Bool) -> Stack<Element> {
        var filteredElements = [Bool]()
        for item in items {
            if element == true { // since this throws a compile error, what property or attribute of Element can I use to return true?
                filteredElements.append(element(item)) // compile error here too: Cannot convert value of type 'Element' (generic parameter of generic struct 'GenericStack') to expected argument type 'Element' (generic parameter of instance method 'filter(_:)')
            }
        }
        return Stack<Element>(items: filteredElements) // compile error: Cannot convert value of type '[Bool]' to expected argument type '[Element]'
        
    }

I tried a different way, but not getting anywhere near the right solution:

// bronze challenge - create a filter(_:) method
    func filter<Bool>(element: (Element) -> Bool) -> Stack<Element> {
        var filteredElements = [Element]()
        for item in items where element(item) { // error message here: Cannot convert value of type 'Bool' to expected condition type 'Swift.Bool'
            filteredElements.append(element(item))
        }
        return Stack<Element>(items: filteredElements)
    }

You’re getting closer. First, filter doesn’t need anything in angle brackets, so lose the <Bool>. Second, you don’t want to put the value returned by the closure into filteredElements, you want to put item in there. Remember, the end result should be another stack of Elements, not a stack of Bools.

Here was my first solution
func filter(_ f: (Element) -> Bool) -> Stack<Element> {
    var filtered_stack = Stack<Element>()
    for item in items where f(item) {
        filtered_stack.push(item)
    }
    return filtered_stack
}
Here's an even simpler one after a few minutes of thinking about it
func filter(_ f: (Element) -> Bool) -> Stack<Element>
{
    return Stack<Element>(items: items.filter(f))
}
1 Like

Thank you for sharing those nuggets, but I like the first one better because it is easier to deal with in the debugger.

True, but it’s re-inventing the wheel. I think that’s the real insight you’re supposed to take away from this exercise.

Thanks, @JonAult

Without looking at your solutions, I got this to build without error:

    func filter(element: (Element) -> Bool) -> Stack<Element> {
        var filteredElements = [Element]()
        for item in items where element(item) {
            filteredElements.append(item)
        }
        return Stack<Element>(items: filteredElements)
    }

Now, I don’t know what the correct argument to input when calling it:

// testing my filter function
var boolStack = Stack<Bool>()
boolStack.push(true)
boolStack.push(false)
boolStack.push(true)

var trueStack = boolStack.filter(true) // compile error here: Cannot convert value of type 'Bool' to expected argument type '(Bool) throws -> Bool'
print(trueStack)

Am I supposed to filter one stack of values by checking whether they’re in another stack of values?

You need to pass in a closure, a function that will evaluate an item on the stack & decide whether it should be included in the filtered list. For example, if you have a stack of Strings, you can filter out anything that doesn’t start with an upper case letter:

stringStack = Stack(items: ["One", "two", "3", "Four"])
var uppercaseStack = stringStack.filter { $0[$0.startIndex].isUppercase }
print(uppercaseStack)   // prints ["One", "Four"]

Refer back to Chapter 13 if you need to refresh your memory on closures.

I think I have it now…

var stringStack = Stack<String>()
stringStack.push("this is a string")
stringStack.push("this is another!")
stringStack.push("742")
stringStack.push("Trip")
stringStack.push("sdfjawoeifasdoifhwe")

let filteredStack = stringStack.filter(element: {$0.count < 5})

print(filteredStack) // yields Stack<String>(items: ["742", "Trip"])
func filter(_ txform: (Element) -> Bool) -> Stack<Element> {
    var filteredItems = [Element]()
    var count = 0
    for item in items {
        if txform(item) {
            filteredItems.append(item)
        }
    }
    return Stack<Element>(items: filteredItems)    }

This is my attempt. For some reason it fails to print any information.