replacing for loop to map method - swift

I am stuck about this goal.
Learn about the map method, and use it in place of the loop that converts the array of characters to an array of strings in updateUI().
I have read Documentation and topics about map, but still all my tries did not work.
//change loop below to map method
for letter in currentGame.formattedWord {
letters.append(String(letter))
}
let wordWithSpacing = letters.joined(separator: " ")
correctWordLabel.text = wordWithSpacing
scoreLabel.text = "Wins: \(totalWins), Losses: \(totalLosses)"
treeImageView.image = UIImage(named: "Tree \(currentGame.incorrectMovesRemaining)")
Thanks for help

The String documentation tells us:
A string is a series of characters, such as "Swift", that forms a collection.
So, you can use map to convert each of these characters to individual strings:
let string = "Hello, world"
let letters = string.map { (character: Character) -> String in
return String(character)
}
Or, more concisely:
let letters = string.map { String($0) }

I did it. the problem was that I left the var letters as an empty array and tried to add characters to this array. Now I realized that this was wrong.
func updateUI() {
let letters = currentGame.formattedWord
let mappedLetters = letters.map { String($0)}
/* for letter in currentGame.formattedWord {
letters.append(String(letter))
} */
Thanks all!

Related

Reverse words with exclusion rules

I would like to get a func which will be able to reverse a string without affecting special characters, preferably using regex, ex:
Input: “Weather is cool 24/7” -> Output: “rehtaeW si looc 24/7”
Input: “abcd efgh” -> Output: “dcba hgfe”
Input: “a1bcd efg!h” -> Output: “d1cba hgf!e”
I was able to write only for all characters without exceptions, I'm a beginner, and I don't know how to use regexes
func reverseTheWord(reverse: String) -> String {
let parts = reverse.components(separatedBy: " ")
let reversed = parts.map{String($0.reversed())}
let reversedWord = reversed.joined(separator: " ")
return reversedWord
}
thanks in advance!
Here is a solution where I first check what type each word is, only letters, no letters or a mix of letters and other characters and handle each differently.
The first two are self explanatory and for the mix one I first reverse the word and remove all non letters and then reinsert the non letters at their original position
func reverseTheWords(_ string: String) -> String {
var words = string.components(separatedBy: .whitespaces)
for (index, word) in words.enumerated() {
//Only letters
if word.allSatisfy(\.isLetter) {
words[index] = String(word.reversed())
continue
}
//No letters
if !word.contains(where: \.isLetter) { continue }
//Mix
var reversed = word.reversed().filter(\.isLetter)
for (index, char) in word.enumerated() {
if !char.isLetter {
index < reversed.endIndex ? reversed.insert(char, at: index) : reversed.append(char)
}
}
words[index] = String(reversed)
}
return words.joined(separator: " ")
}

Splitting String after Comma into Tuples Swift

let input = "hello, world song"
I have an input string as above.
So i can easily use this partial string something like this
output.0 // hello
output.1 // world song
I tried something like this How to split a string by new lines in Swift but i could not exactly what i want.
Can someone write an extension for this please in a nice way?
I would do something like this:
extension String {
func splitAtFirst(_ separator: Character) -> (head: Substring, tail: Substring?) {
guard let indexOfSeparator = self.firstIndex(of: separator) else {
return (head: Substring(self), tail: nil)
}
let indexAfterSeparator = self.index(indexOfSeparator, offsetBy: +1, limitedBy: self.endIndex)!
return (
head: self[..<indexOfSeparator],
tail: self[indexAfterSeparator...]
)
}
}
let (head, tail) = "abc, def, ghi".splitAtFirst(",")
print(head) // abc
print(tail as Any) // Optional(" def, ghi")
This returns Substrings, which gives you an efficient way to do a lot of processing on an input string without causing a bunch of copies along the way. Of course, you should promote these substrings to full on strings after you've finished processing them.
You can use an extension as below:
extension StringProtocol {
var tupleOfSplittedString: (String,String) {
if !self.isEmpty {
let splitted = self.split(separator: ",").map { String($0)}
let firstPart = splitted[0]
let otherPart = String(splitted[1...].joined().dropFirst())
return (firstPart,otherPart)
}
return ("","")
}
}
let input = "hello, world song"
let resultOfFirstPart = input.tupleOfSplittedString.0 // hello
let resultOfOtherPart = input.tupleOfSplittedString.1 // world song
This code uses the .components method to split a string by a substring. I have tested this, and it was successful, even if the String is blank (it returns ("", "") in that case)
Line 4 of this code is a bit hard to read, but you can split it up into multiple lines of code if you would like.
import Foundation
extension String {
var tuple: (String, String) {
return self.components(separatedBy: ",").count == 2 ? ((self.components(separatedBy: ",")[0], self.components(separatedBy: ",")[1] )) : ("", "")
}
}
var input = "hello, world song"
print(input.tuple.0) //prints hello
print(input.tuple.1) //prints world song

Remove non numeric characters from string having multiple float values using for loop

I have a string having characters and float values in a list like let string = "12.1gh34.5abc32.1". i want to remove characters from string and result will be shown in array with float values. is there any solution for this.
Split the string using letters as the separator. Remove empty strings from the result. Map the remaining number strings into real numbers.
let string = "12.1gh34.5abc32.1"
let numbers = string.components(separatedBy: .letters)
.filter { !$0.isEmpty }
.compactMap { Double($0) }
The output is:
[12.1, 34.5, 32.1]
If you want to deal with anything that isn't a decimal digit or comma, you can replace .letters with:
CharacterSet(charactersIn: "0123456789.").inverted
You can use Collection split method and set omittingEmptySubsequences to true:
extension StringProtocol {
func notContains(_ element: Element) -> Bool {
return !contains(element)
}
var numbers: [SubSequence] {
return split(maxSplits: Int.max, omittingEmptySubsequences: true, whereSeparator: "0123456789.".notContains)
}
}
let text = "12.1gh 34.5abc 32.5"
let result = text.numbers // ["12.1", "34.5", "32.5"]
let nums = result.flatMap(Double.init) // [12.1, 34.5, 32.5]

Remove the first six characters from a String (Swift)

What's the best way to go about removing the first six characters of a string? Through Stack Overflow, I've found a couple of ways that were supposed to be solutions but I noticed an error with them. For instance,
extension String {
func removing(charactersOf string: String) -> String {
let characterSet = CharacterSet(charactersIn: string)
let components = self.components(separatedBy: characterSet)
return components.joined(separator: "")
}
If I type in a website like https://www.example.com, and store it as a variable named website, then type in the following
website.removing(charactersOf: "https://")
it removes the https:// portion but it also removes all h's, all t's, :'s, etc. from the text.
How can I just delete the first characters?
In Swift 4 it is really simple, just use dropFirst(n: Int)
let myString = "Hello World"
myString.dropFirst(6)
//World
In your case: website.dropFirst(6)
Why not :
let stripped = String(website.characters.dropFirst(6))
Seems more concise and straightforward to me.
(it won't work with multi-char emojis either mind you)
[EDIT] Swift 4 made this even shorter:
let stripped = String(website.dropFirst(6))
length is the number of characters you want to remove (6 in your case)
extension String {
func toLengthOf(length:Int) -> String {
if length <= 0 {
return self
} else if let to = self.index(self.startIndex, offsetBy: length, limitedBy: self.endIndex) {
return self.substring(from: to)
} else {
return ""
}
}
}
It will remove first 6 characters from a string
var str = "Hello-World"
let range1 = str.characters.index(str.startIndex, offsetBy: 6)..<str.endIndex
str = str[range1]
print("the end time is : \(str)")

swift: how can I delete a specific character?

a string such as ! !! yuahl! ! , I want delete ! and , when I code like this
for index in InputName.characters.indices {
if String(InputName[index]) == "" || InputName.substringToIndex(index) == "!" {
InputName.removeAtIndex(index)
}
}
have this error " fatal error: subscript: subRange extends past String end ", how should I do? THX :D
Swift 5+
let myString = "aaaaaaaabbbb"
let replaced = myString.replacingOccurrences(of: "bbbb", with: "") // "aaaaaaaa"
If you need to remove characters only on both ends, you can use stringByTrimmingCharactersInSet(_:)
let delCharSet = NSCharacterSet(charactersInString: "! ")
let s1 = "! aString! !"
let s1Del = s1.stringByTrimmingCharactersInSet(delCharSet)
print(s1Del) //->aString
let s2 = "! anotherString !! aString! !"
let s2Del = s2.stringByTrimmingCharactersInSet(delCharSet)
print(s2Del) //->anotherString !! aString
If you need to remove characters also in the middle, "reconstruct from the filtered output" would be a little bit more efficient than repeating single character removal.
var tempUSView = String.UnicodeScalarView()
tempUSView.appendContentsOf(s2.unicodeScalars.lazy.filter{!delCharSet.longCharacterIsMember($0.value)})
let s2DelAll = String(tempUSView)
print(s2DelAll) //->anotherStringaString
If you don't mind generating many intermediate Strings and Arrays, this single liner can generate the expected output:
let s2DelAll2 = s2.componentsSeparatedByCharactersInSet(delCharSet).joinWithSeparator("")
print(s2DelAll2) //->anotherStringaString
I find that the filter method is a good way to go for this sort of thing:
let unfiltered = "! !! yuahl! !"
// Array of Characters to remove
let removal: [Character] = ["!"," "]
// turn the string into an Array
let unfilteredCharacters = unfiltered.characters
// return an Array without the removal Characters
let filteredCharacters = unfilteredCharacters.filter { !removal.contains($0) }
// build a String with the filtered Array
let filtered = String(filteredCharacters)
print(filtered) // => "yeah"
// combined to a single line
print(String(unfiltered.characters.filter { !removal.contains($0) })) // => "yuahl"
Swift 3
In Swift 3, the syntax is a bit nicer. As a result of the Great Swiftification of the old APIs, the factory method is now called trimmingCharacters(in:). Also, you can construct the CharacterSet as a Set of single-character Strings:
let string = "! !! yuahl! !"
string.trimmingCharacters(in: [" ", "!"]) // "yuahl"
If you have characters in the middle of the string you would like to remove as well, you can use components(separatedBy:).joined():
let string = "! !! yu !ahl! !"
string.components(separatedBy: ["!", " "]).joined() // "yuahl"
H/T #OOPer for the Swift 2 version
func trimLast(character chars: Set<Character>) -> String {
let str: String = String(self.reversed())
guard let index = str.index(where: {!chars.contains($0)}) else {
return self
}
return String((str[index..<str.endIndex]).reversed())
}
Note:
By adding this function in String extension, you can delete the specific character of string at last.
for index in InputName.characters.indices.reversed() {
if String(InputName[index]) == "" || InputName.substringToIndex(index) == "!" {
InputName.removeAtIndex(index)
}
}
Also you can add such very helpful extension :
import Foundation
extension String{
func exclude(find:String) -> String {
return stringByReplacingOccurrencesOfString(find, withString: "", options: .CaseInsensitiveSearch, range: nil)
}
func replaceAll(find:String, with:String) -> String {
return stringByReplacingOccurrencesOfString(find, withString: with, options: .CaseInsensitiveSearch, range: nil)
}
}
you can use this:
for example if you want to remove "%" the percent from 10%
if let i = text.firstIndex(of: "%") {
text.remove(at: i) //10
}