I have an array with a set of three-letter words that will be the foundation of a game I am working on. I am trying to replace the second character of all these words with an underscore in my UILabel. The user will have to tap the correct vowel to complete the word.
let games: [Game] = {
let firstGame = Game(question: "1", answer: "BAT", choice_1: "A", choice_2: "O", choice_3: "U", choice_4: "E", image: "_bat", audio: "bat.wav")
let secondGame = Game(question: "2", answer: "BIN", choice_1: "A", choice_2: "O", choice_3: "U", choice_4: "E", image: "_bin", audio: "bin.wav")
let thirdGame = Game(question: "3", answer: "BOX", choice_1: "A", choice_2: "O", choice_3: "U", choice_4: "E", image: "_box", audio: "box.wav")
return [firstGame, secondGame, thirdGame]
}()
I found the replacingOccurrences functionality, but this one only replaces a single letter or set. What is the easiest way to replace all my vowels with the _ character.
var game: Game? {
didSet {
questionLabel.text = "Question \(String(describing: game!.question)) of 10"
if (game?.image) != nil {
imageView.image = UIImage(named: (game?.image)!)
}
if let answerContent = game?.answer {
answerField.text = answerContent.replacingOccurrences(of: "A", with: "_")
answerField.addTextSpacing()
}
}
}
Replace vowels…
let vowels = CharacterSet(charactersIn: "AEIOU")
var string = "CAT"
if let range = string.rangeOfCharacter(from: vowels) {
string.replaceSubrange(range, with: "_")
}
print(string) // C_T
Replace second character…
let start = string.index(after: string.startIndex)
// Only 1 character, so using a closed range with start == end
let range = start...start
string.replaceSubrange(range, with: "_")
print(string) // C_T
Related
In Swift I have a string like:
let str = "5~895893799,,6~898593679,,7~895893679,,8~895893799,,5~895893799,,6~898593679,,7~895893679,,8~895893799";
From this I need to get only the number which is before "~" which is [5,6,7,8,5,6,7,8]
How can I achieve this?
Make use of components(separatedBy:) and compactMap.
let str = "5~895893799,,6~898593679,,7~895893679,,8~895893799,,5~895893799,,6~898593679,,7~895893679,,8~895893799"
let nums = str.components(separatedBy: ",,")
.compactMap { $0.components(separatedBy: "~").first }
That gives the string array:
["5", "6", "7", "8", "5", "6", "7", "8"]
If you want an array of Int, add:
.compactMap { Int($0) }
to the end.
let nums = str.components(separatedBy: ",,")
.compactMap { $0.components(separatedBy: "~").first }
.compactMap { Int($0) }
That gives:
[5, 6, 7, 8, 5, 6, 7, 8]
You could define this regular expression:
let regex = try! NSRegularExpression(pattern: #"\d+(?=~)"#)
\d : matches any digit
+ : this is the one or more quantifier
(?=~) : Positive lookahead for "~"
and use it like so:
let range = NSRange(location: 0, length: (str as NSString).length)
let matches = regex.matches(in: str, range: range)
let strings: [String] = matches.map { match in
let subRange = match.range
let startIndex = str.index(str.startIndex, offsetBy: subRange.lowerBound)
let endIndex = str.index(str.startIndex, offsetBy: subRange.upperBound)
let subString = String(str[startIndex..<endIndex])
return subString
}
let numbers = strings.compactMap(Int.init) //[5, 6, 7, 8, 5, 6, 7, 8]
I'm new to swift programming and struggling with a simple method that I want to use. Ive added random letters to an array and I want a user to type in a word. The method should then iterate through each letter of that word and return the index of each letter so it would output a number code for the word. Eg. If I input "swift" it should return "185103", number relevant to the position of each letter though. (See my array). At the moment it has no loop so it's only returning one index for one letter. Here is what I have so far:
print("Please enter the word:")
if let inputCode = readLine(){
let pidgeonCode = ["s", "a", "t", "p", "i", "n", "m", "w", "g", "f", "c", "k"]
let location = pidgeonCode.index(of:inputCode)
print("Your word is: \(location!)")
} else{
print("Type something!!")
}
Thank you very much!
I managed to do it, thanks. Here is the code I used for future help.
print("Please enter the word:")
if let inputCode = readLine(){
let numberOf = inputCode.count
var loop = 0
let pidgeonCode = ["#", "s", "a", "t", "p", "i", "n", "m", "d", "g", "o", "c", "k"]
var wordcode = "Code:"
while loop < numberOf{
let x = inputCode.index(inputCode.startIndex, offsetBy: loop)
let result = inputCode[x]
let location = pidgeonCode.index(of:"\(result)")
wordcode = wordcode + "\(location!)"
loop = loop + 1
}
print(wordcode)
} else{
print("Type something!!")
}
I am trying to program a simple function and am having some trouble. The purpose of the function is to take a String and if the String does not start with a consonant, remove each vowel until you reach the first consonant. For example if the given String was "eat" the function would return "t". If the given String was "awesome" it would return "wesome"
Below is my code, it compiles without error but I cannot get the desired output. Right now it just outputs an empty string. id appreciate any advice, Thanks
This would be the correct and efficient solution:
func removeFirstLetter(word: String) -> String {
var lyricalWord = word
let vowelArray = ["a", "e", "i", "o", "u", "y"]
for _ in lyricalWord {
// We are moving these to the loop so every time we get updated first character
var firstCharacter = lyricalWord[lyricalWord.startIndex]
var str = String(firstCharacter)
if vowelArray.contains(str) {
lyricalWord.remove(at: lyricalWord.startIndex)
} else {
// If this time the first character is consonant that means our string is ready and we can return it and finish the loop
return lyricalWord
}
}
return lyricalWord
}
print(removeFirstLetter(word: "aeiouty"))
But it can even be improved!
In your loop you iterate every time through the whole array of vowel. However, you have a nice structure called Set which works like hash table.
In simple words, while the function "contains():" calls your array 6 times to compare the letter with every vowel, the same implementation with Set makes only 1 call(not always, but most of the time)! And it's especially profitable when you gonna have bigger collections of data to compare with.
So, here goes the implementation with Set:
func removeFirstLetter(word: String) -> String {
var lyricalWord = word
let vowelArray: Set<String> = ["a", "e", "i", "o", "u", "y"] // The only change is here!
for _ in lyricalWord {
var firstCharacter = lyricalWord[lyricalWord.startIndex]
var str = String(firstCharacter)
if vowelArray.contains(str) {
lyricalWord.remove(at: lyricalWord.startIndex)
} else {
return lyricalWord
}
}
return lyricalWord
}
print(removeFirstLetter(word: "aeiouty"))
Two lines below the position are invalid.
let firstCharacter = lyricalworld[lyricalworld.startIndex]
let str = String(firstCharacter)
Please put it inside the for door.
for _ in lyricalworld {
let firstCharacter = lyricalworld[lyricalworld.startIndex]
let str = String(firstCharacter)
if vowelArray.contains(str){
lyricalworld.remove(at: lyricalworld.startIndex)
}
}
Full Source
func removeFirstLetter(word: String) -> String{
var lyricalworld = word
let vowelArray = ["a", "e", "i", "o", "u", "y"]
for _ in lyricalworld {
let firstCharacter = lyricalworld[lyricalworld.startIndex]
let str = String(firstCharacter)
if vowelArray.contains(str){
lyricalworld.remove(at: lyricalworld.startIndex)
}
}
return lyricalworld
}
suppose i have a array that have 10 elements. say,
var ArrayElemts : ["1","2","3","4","5","6","7","8","9","10","11"]
Now how can i keep the elements from 0 t0 5 in one array set and 6 to 10 to another array set?
Use [0...5] to create an ArraySlice and then Array to convert that back to an array:
var arrayElemts = ["1","2","3","4","5","6","7","8","9","10","11"]
let first = Array(arrayElemts[0...5])
let second = Array(arrayElemts[6...10])
print(first) // ["1", "2", "3", "4", "5", "6"]
print(second) // ["7", "8", "9", "10", "11"]
The easiest option is the following:
let partition1 = array.filter { Int($0) ?? 0 <= 5 }
let partition2 = array.filter { Int($0) ?? 0 > 5 }
Conversion to numbers should be the first step though. You should never work with strings as if they were numbers.
let numbers = array.flatMap { Int($0) }
let partition1 = numbers.filter { $0 <= 5 }
let partition2 = numbers.filter { $0 > 5 }
If we suppose the array is sorted, there are easier options:
let sorted = numbers.sorted()
let partition1: [Int]
let partition2: [Int]
if let partition2start = sorted.index(where: { $0 > 5 }) {
partition1 = Array(sorted.prefix(upTo: partition2start))
partition2 = Array(sorted.suffix(from: partition2start))
} else {
partition1 = sorted
partition2 = []
}
which is what the native partition method can do:
var numbers = array.flatMap { Int($0) }
let index = numbers.partition { $0 > 5 }
let partition1 = Array(numbers.prefix(upTo: index))
let partition2 = Array(numbers.suffix(from: index))
Note the method changes the original array.
Breaking the array up into N-sized chunks
The other answers show you how to "statically" partition the original array in different arrays using ArraySlice:s. Given your description, possibly you want to, generally, break up your original array into N-sized chunks (here: n = 5).
We could use the sequence(state:next) to implement such a chunk(bySize:) method as an extension to Collection:
extension Collection {
func chunk(bySize size: IndexDistance) -> [SubSequence] {
precondition(size > 0, "Chunk size must be a positive integer.")
return sequence(
state: (startIndex, index(startIndex, offsetBy: size, limitedBy: endIndex) ?? endIndex),
next: { indices in
guard indices.0 != self.endIndex else { return nil }
indices.1 = self.index(indices.0, offsetBy: size, limitedBy: self.endIndex) ?? self.endIndex
return (self[indices.0..<indices.1], indices.0 = indices.1).0
}).map { $0 }
}
}
Applied to your example:
var arrayElements = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"]
let partitions = arrayElements.chunk(bySize: 5)
/* [["1", "2", "3", "4", "5"],
["6", "7", "8", "9", "10"],
["11"]] */
The chunk(bySize:) method will break up the array into bySize-sized chunks, as well as (possible) a smaller chunk for the final partition.
However, as much as I'd like to try to use the sequence(state:next) function (not needing to use any mutable intermediate variables other than state), the implementation above is quite bloated and difficult to read, so (as for so many other cases ...) we are probably better off simply using a while loop:
extension Collection {
func chunk(bySize size: IndexDistance) -> [SubSequence] {
precondition(size > 0, "Chunk size must be a positive integer.")
var chunks: [SubSequence] = []
var from = startIndex
while let to = index(from, offsetBy: size, limitedBy: endIndex) {
chunks.append(self[from..<to])
from = to
}
if from != endIndex { chunks.append(self[from..<endIndex]) }
return chunks
}
}
lol I don't see why there are so complicated answers here
(Consider the "array" variable as is -> [Int], not [Any])
So the first approach is just for Number types.
The second one should do it
Simply:
let array = [0,1,2,3,4,5,6,7,8,9,10]
//For instance..
var arrayA = ["A","B","C","D","E","F","G"]
//First 6 elements
let arrayOfFirstFour = array.filter({
return $0 <= 5 ? true : false
})
//Remaining elements:
let restOfArray = array.filter({
return $0 > 5 ? true : false
})
let elementsToFourth = arrayA.prefix(upTo: 4)
let elementsAfterFourth = arrayA.suffix(from: 4)
print(arrayOfFirstFour)
print(restOfArray)
print(elementsToFourth)
print(elementsAfterFourth)
//[0, 1, 2, 3, 4, 5]
//[6, 7, 8, 9, 10]
//["A", "B", "C", "D"]
//["E", "F", "G"]
I have a string as shown below,
let newString : String = "12","34","56","78","910","1112","1314","1516","1718","1920","2122","2324","2526","2729".
i want to separate string with "4 string each" string e.g. "12","34","56","78" and "910","1112","1314","1516" and so on.
Can we achieve this by using range or something else?
Note :- newString is not static data it will come from webservice
You can try like this way, first create array from String, then make chunk array from it and then join the string from array.
let newString = "1,2,3,4,5,6,7,8,9,10,11,12"
let array = newString.components(separatedBy: ",") // ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
let chunkSize = 4
let chunksArray = stride(from: 0, to: array.count, by: chunkSize).map {
Array(array[$0..<min($0 + chunkSize, array.count)])
}
let subArray = chunksArray.map { $0.joined(separator: ",") }
// ["1,2,3,4", "5,6,7,8", "9,10,11,12"]
Edit: You can merge last two action with single like this way.
let subArray = stride(from: 0, to: array.count, by: chunkSize).map {
array[$0..<min($0 + chunkSize, array.count)].joined(separator: ",")
}
// ["1,2,3,4", "5,6,7,8", "9,10,11,12"]
First generate an array from string:
let newString = "1,2,3,4,1234,1235,1236,1238,678,679"
let newStringArray = newString.componentsSeparatedByString(",")
Then run for loop and add string using joinWithSeparator
You could split string the by , like: let strArr = newString.components(separatedBy: ","), then split the strArr to arrays containing 4 elements, and join each resulting array by ,. Hope this helps, good luck!