iOS Closures in Swift First Class Functions Higher Order Functions

Louis Mark
Louis Mark
8,882 Points

Why isn't my code accepted? (Closures)

I'm in part three of the challenge, where it instructs us to "On the string "Hello, World!", call the transform function and use the removeVowels(from:) function as an argument. Assign the result to a constant named result."

I've got part one and two correct. Part 3 just needs me to submit this code: "Hello, World!".transform(removeVowels)

Why isn't this working? Thanks!

functions.swift
// Enter your code below
extension String {
    func transform(_ function: (String) -> String) -> String {
        return self.transform(function)
    }
}

extension Character {
    var isVowel: Bool {
        let vowels: [Character] = ["a", "e", "i", "o", "u"]
        return vowels.contains(self)
    }
}

func removeVowels(from string: String) -> String {
    var characterArray = string.characters
    for character in characterArray {
        if character.isVowel {
            if let index = characterArray.index(of: character){
                characterArray.remove(at: index)
            }
        }
    }
    var returnString: String = ""
    for character in characterArray {
        returnString.append(character)
    }

    return returnString
}

let result = "Hello, World!".transform(removeVowels)

6 Answers

Scott Baumbich
Scott Baumbich
20,746 Points

The question hint provide is very useful, however the .characters string method seems to have gone through some ups and downs in Swift 2 & 3 as it was not seen as a collection type.

Here's just one more way to solve this challenge. Hope it helps!

https://useyourloaf.com/blog/updating-strings-for-swift-4/

extension String {
    func transform(_ argument: (String) -> String) -> String {
        return argument(self)
    }
}

func removeVowels(from someString: String) -> String {
    var orgString = someString.lowercased()
    var newString = ""

    for letter in someString.characters {
        if letter == "a" || letter == "e" || letter == "i" || letter == "o" || letter == "u" {
            //Do not add the letter to newString because it is a vowel
        } else {
            newString.append(letter)
        }
    }
    return newString
}

let result = "Hello, World!".transform(removeVowels)
Xavier D
PRO
Xavier D
Pro Student 5,835 Points

My answer too is similar ito Jeff's...I didn't need to extend another object (but I did like seeing it in action), sometimes conciseness is best....but I couldn't help to have this as my remove vowel var:

var aEIOU = ""

and although it's technically not a vowel, in my for-in loop and if statement I had:

vowel == "y"

and the condition worked for me in the code challenge because I guess because sometimes y is a vowel when you encounter words like "fly, "my", "cry", etc. hmm...maybe I should've named it:

var aEIOUSometimesY = ""

XD

Xavier D
PRO
Xavier D
Pro Student 5,835 Points

Hi,

I just tried to run your code and I keep getting the following error right here:

let result = "Hello, World!".transform(removeVowels)

when assigning to result, Here's the following error:

" EXC_BAD_ACCESS (code=2, address=0x7fff4fbc1fb0).
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation."

With that error, I was not able to get past part 1 of the challenge. However in part one, the instructions state:

//In an extension to the String type, declare a function named transform. The function should accept as an argument another function of type (String) -> String. For this argument, let's omit the external label. The transform function should also return a String.
//In the body of the method, return the result of applying the function argument to self.

However, in the body of the method, you did not return self as an argument to the method, but used dot notation to return self's transform method and passed in the method's internal parameter name as the argument. Here is what I saw wrong:

return self.transform(function)

It has to be the other way around--return the internal parameter name with self as its argument. When I fixed that, I was able to to get thru all 3 parts of the challenge without any hiccups in the 3rd part.

Good Job!

If you still have an issue after you fix that return, please repost the error you're getting...but I think you got it!

Jeff McDivitt
Jeff McDivitt
23,959 Points

Hi Louis -

Like Xavier stated above I believe too that this is your issue;; however you are creating a lot of code that you do not actually need for this task. The below is how I completed the challenge:

extension String{

    func transform(_ argument : (String) -> String) -> String {
        return  argument(self)
    }
}

func removeVowels(from value: String) -> String {
    var output = ""

    for char in value.characters {
        if !(char == "a" || char == "A" || char == "e" || char == "e"
            || char == "i" || char == "I" || char == "o" || char == "O"
            || char == "u" || char == "U") {
            output.append(char)
        }
    }
    return output
}

let result = "Hello, World!".transform(removeVowels)
Xavier D
PRO
Xavier D
Pro Student 5,835 Points

Hi Louis and Jeff,

You wanna know something? Even though the code challenge accepted my sometimes y condition:

vowel == "y"

...it wasn't really sometimes y, but more like always y if y is present...and that would give errors if working with words having vowels and y. You would definitely get a runtime error if you used "you", and if you used "you" in the transform method in my code. "You" would literally disappear if the if is like this if in this code:

extension String
{
    func transform( _ funC: (String)-> String ) -> String
    {
        return funC(self)
    }
}

func removeVowels(from word: String) -> String
{
    var aEIOU = ""

    for letter in word.characters
    {
        if !(letter == "a" || letter == "e" || letter == "i" || letter == "o" || letter == "u" || letter == "y"  ||
            letter == "A" || letter == "E" ||  letter == "I" || letter == "O" || letter == "U" || letter == "Y" )
        {
            aEIOU.characters.append(letter)
        }
    }

    return aEIOU
}

"you".transform(removeVowels)

...if "you" goes just like that, you wouldn't be running good code using the above. I just can't let that happen to "you" without sometimes y being applied correctly, because if it were correct, only "u" and "o" would go and sometimes y wouldn't apply because the vowels are "o" and "u" and not y this time. Therefore, I owe you some correct code:

import Foundation

extension String{func transform(_ funC:(String)->String)->String{return funC(self)}}

func removeVowels(from word: String)->String
{
    var aEIOU=0;var noAEIOUSometimesY="";var whyWordWithY=0;var wordsWithNo_=[String]()

    func aEIOUOrY(word: String){aEIOUSometimesY(word:word);switch true{case aEIOU==0&&whyWordWithY>0:whyOnlyWithY(word:word)default: sometimesWithY(word:word)}}
    func aEIOUSometimesY(word: String){for letter in word.characters{switch letter
    {case"a":aEIOU+=1 case"e":aEIOU+=1 case"i":aEIOU+=1 case"o":aEIOU+=1 case"u":aEIOU+=1 case"y":whyWordWithY+=1
     case"A":aEIOU+=1 case"E":aEIOU+=1 case"I":aEIOU+=1 case"O":aEIOU+=1 case"U":aEIOU+=1 case"Y":whyWordWithY+=1;default: break}}}
    func sometimesWithY(word: String){for letter in word.characters{if !(letter=="a"||letter=="e"||letter=="i"||letter=="o"||letter=="u"||letter=="A"||letter=="E"||letter=="I"||letter=="O"||letter=="U"){noAEIOUSometimesY.characters.append(letter)}}}
    func remove_s(word: String){wordsWithNo_ = word.components(separatedBy:" ")}
    func why_Input(){for word in 0..<wordsWithNo_.count{aEIOUOrY(word: String(wordsWithNo_[word]));aEIOU=0;whyWordWithY=0}}
    func whyOnlyWithY(word: String){for letter in word.characters {if !(letter=="y"||letter=="Y"){noAEIOUSometimesY.characters.append(letter)}}}
    func whyWith_(word: String){switch true{case word.contains(" "):remove_s(word: word);why_Input();default: aEIOUOrY(word: word)}}

    whyWith_(word: word);return noAEIOUSometimesY
}

let result = "funny".transform(removeVowels(from:))
let result2 = "You".transform(removeVowels(from:))
let result3 = "fly".transform(removeVowels(from:))
let result4 = "Hello World!".transform(removeVowels(from:))
let result5 = "Why is y is a vowel in a word with no vowels".transform(removeVowels(from:))
let result6 = "Sometimes i before e expect after c".transform(removeVowels(from:))
let result7 = "Not all ys are flying away from this phrase. Yay! That's fly!".transform(removeVowels(from:))

To prevent “you” from completely disappearing, I added come variables to track the vowel count to better determine when to remove y from a word like “you”, like whyWordWithY. Why did I name the var “whyWordWithY”? Well I wanted to name it as, “wordWith?”, as if I’m asking question but, then that would make the var an optional, and if I did that, then I would have to unwrap in order to use the value, and I didn’t want that—so instead, I named it whyWordWithY. I also added some additional functions as well…

"fnny"
"Y"
"fl"
"HllWrld"
"Whssvwlnwrdwthnvwls"
"Smtmsbfrxpctftrc"
"Ntllsrflyngwyfrmthsphrs.Yy"

Let me know if anyone comes across a word (even a phrase) that doesn't work..now there's more functions, and I needed Foundation in order to add more functionality to String. Oh, and so sorry if I scrunched up the code...the code was getting extra long andI'm working with an iPad Mini for my display and it's preferable to compact the code since the Mini's real estate small. I tried to make it easy by grouping functions together and sorted them in abc order.

XD

One Weru
One Weru
47,620 Points

A lot of folks seem to be using an if block. I believe that using a switch block is more concise, like so:

func removeVowels(from oldString: String) -> String {
  var newString: String = ""
  for letter  in oldString.characters {
    switch letter {
      case "a", "e", "i", "o", "u", "A", "E", "I", "O", "U": break
      default: newString.append(letter)
    }
  }
  return newString
}

I hope this benefits someone.