8

I'm learning swift. I've been trying this in Playground. I have no idea why the string is not being capitalized here. Or is there any other way to capitalize the string inside the array directly?

Here's my code.

var dogNames = ["Sean", "fido", "Sarah", "Parker", "Walt", "abby", "Yang"]

for index in 0..<dogNames.count {
    var dogName = dogNames[index].capitalizedString
    dogNames.removeAtIndex(index)
    dogNames.append(dogName)
}

When I try to display again the variable dogNames. The strings inside are not being capitalized.

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Rhenz
  • 2,293
  • 1
  • 14
  • 14

7 Answers7

14

update: Xcode 8.2.1 • Swift 3.0.2

var dogNames = ["Sean", "fido", "Sarah", "Parker", "Walt", "abby", "Yang"]

for (index, element) in dogNames.enumerated() {
    dogNames[index] = element.capitalized
}

print(dogNames)   // "["Sean", "Fido", "Sarah", "Parker", "Walt", "Abby", "Yang"]\n"

This is a typical case for using map():

let dogNames1 = ["Sean", "fido", "Sarah", "Parker", "Walt", "abby", "Yang"].map{$0.capitalized}

A filter() sample:

let dogNamesStartingWithS = ["Sean", "fido", "Sarah", "Parker", "Walt", "abby", "Yang"].filter{$0.hasPrefix("S")}

dogNamesStartingWithS   // ["Sean", "Sarah"]

you can combine both:

let namesStartingWithS = ["sean", "fido", "sarah", "parker", "walt", "abby", "yang"].map{$0.capitalized}.filter{$0.hasPrefix("S")}

namesStartingWithS   // ["Sean", "Sarah"]

You can also use the method sort (or sorted if you don't want to mutate the original array) to sort the result alphabetically if needed:

let sortedNames = ["sean", "fido", "sarah", "parker", "walt", "abby", "yang"].map{$0.capitalized}.sorted()

sortedNames  // ["Abby", "Fido", "Parker", "Sarah", "Sean", "Walt", "Yang"]
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • hmmm cool. Haven't heard/learn yet the map function. Thanks for this! – Rhenz Feb 24 '15 at 08:00
  • it is pretty easy just think about $0 being each item of the array – Leo Dabus Feb 24 '15 at 08:03
  • @LeonardoSavioDabus could you explain about map or advice some link ? thank you so much :) – Huy Nghia Feb 24 '15 at 08:06
  • 1
    map will loop through your whole array applying the closure method to all items. $0 is the item at that particular index. $0.capitalizedString is the same as yourArray[index].capitalizedString from the first to the last element – Leo Dabus Feb 24 '15 at 08:09
  • filter is the same but it will keep the elements only if the comparison specified in the closure is met – Leo Dabus Feb 24 '15 at 08:11
  • Can we simple compare it to a "For in loop" ? – Rhenz Feb 24 '15 at 08:12
  • it is a single loop through all elements – Leo Dabus Feb 24 '15 at 08:12
  • if you want all elements lowercase just change it to $0.lowercaseString or all upper $0.uppercaseString – Leo Dabus Feb 24 '15 at 08:13
  • I have added a filter and a combination of both – Leo Dabus Feb 24 '15 at 08:19
  • Hey thanks for this. But still I find it hard to read. Don't you think so too? – Rhenz Feb 24 '15 at 09:57
  • it takes the string and break it down to an array of characteres Array($0), then it gets the .first character of that array, converts it back to a String String(result ) and compares it with the letter s. String(result ) == "S". If the condition is met it keep the item otherwise it discards it – Leo Dabus Feb 24 '15 at 10:15
  • `Cannot assign through subscript: subscript is get-only` error – Nike Kov Jun 08 '16 at 14:46
3

Try to use following code :

var dogNames = ["Sean", "fido", "Sarah", "Parker", "Walt", "abby", "Yang"]

for index in 0..<dogNames.count {
    var dogName = dogNames[index].capitalizedString
    dogNames[index]=dogName
}

Output :

[Sean, Fido, Sarah, Parker, Walt, Abby, Yang]

Ashish Kakkad
  • 23,586
  • 12
  • 103
  • 136
  • Yeah it worked. I'm so lame I didn't see because of removing an item, some items are being skipped. Anyway is there also a way to check the String if it is already capitalized so that it could lessen the process? – Rhenz Feb 24 '15 at 07:33
  • you have to check character by `NSCharacterSet.uppercaseLetterCharacterSet()` – Ashish Kakkad Feb 24 '15 at 07:37
2

By removing from the middle of the array and then appending to the end, you end up skipping over some items. Here is what the array looks like at each step:

[Sean, fido, Sarah, Parker, Walt, abby, Yang]
[fido, Sarah, Parker, Walt, abby, Yang, Sean] (index=0; Sean moved to end)
[fido, Parker, Walt, abby, Yang, Sean, Sarah] (index=1; Sarah moved to end)
[fido, Parker, abby, Yang, Sean, Sarah, Walt] (index=2; Walt moved to end)
[fido, Parker, abby, Sean, Sarah, Walt, Yang]
[fido, Parker, abby, Sean, Walt, Yang, Sarah]
[fido, Parker, abby, Sean, Walt, Sarah, Yang]
[fido, Parker, abby, Sean, Walt, Sarah, Yang]

If you want to keep the array intact, it would make more sense to replace at the same index that you took it from:

dogNames[index] = dogName

But you can do this more elegantly by using Array.map to process each item independently, and not have to deal with indexes at all:

    let dogNames = ["Sean", "fido", "Sarah", "Parker", "Walt", "abby", "Yang"]
    let capitalDogNames = dogNames.map({ (dogName) -> String in
        return dogName.capitalizedString
    })
Phssthpok
  • 1,629
  • 1
  • 14
  • 21
  • Oh I see. I get it! I'm so lame. What should I do instead? I just want to capitalized each string. – Rhenz Feb 24 '15 at 07:29
  • Yeah. The `map` function takes a closure and applies it to each item in an array, and gives you an array of the result. It is a little picky about what type of closure it accepts. You have to specify the return value for each item: in this case `String`. – Phssthpok Feb 24 '15 at 07:51
2

To answer my own question as well. Summarizing everything I found in the answers here. I came up with this solution. This is what I did to fix this with less process.

var dogNames = ["Sean", "fido", "Sarah", "Parker", "Walt", "abby", "Yang"]


for index in 0..<dogNames.count {

    if dogNames[index] != dogNames[index].capitalizedString {
        var dogName = dogNames[index].capitalizedString
        dogNames[index] = dogName
    }

}
Rhenz
  • 2,293
  • 1
  • 14
  • 14
1

Use .uppercaseString to capitalize all characters.

Bonga Mbombi
  • 175
  • 1
  • 11
1

You have to perform the loop in reverse order:

for index in reverse(0..<dogNames.count)

The reason is that when you remove an element from an array, all elements after the removed one are shifted back by one position, hence having their index changed - whereas all elements before do not have any index change. By navigating in reverse order you are sure that the items still to process haven't had their index changed.

Antonio
  • 71,651
  • 11
  • 148
  • 165
1

Here is the simplest way to do it in swift 3.0:

var dogNames = ["Sean", "fido", "Sarah", "Parker", "Walt", "abby", "Yang"]

dogNames = dogNames.map {$0.capitalized}
print("dogNames: \(dogNames)")
Zulqarnain Mustafa
  • 1,615
  • 2
  • 22
  • 25