Basic question
I have 2 strings. I want to add one string to another? Here's an example:
var secondString= "is your name."
var firstString = "Mike, "
Here I have 2 strings. I want to add firstString to secondString, NOT vice versa. (Which would be: firstString += secondString.)
More detail
I have 5 string
let first = "7898"
let second = "00"
let third = "5481"
let fourth = "4782"
var fullString = "\(third):\(fourth)"
I know for sure that third and fourth will be in fullString, but I don't know about first and second.
So I will make an if statement checking if second has 00. If it does, first and second won't go in fullString. If it doesn't, second will go intofullString`.
Then I will check if first has 00. If it does, then first won't go inside of fullString, and if not, it will go.
The thing is, I need them in the same order: first, second, third fourth. So in the if statement, I need a way to potentially add first and second at the beginning of fullString.
Re. your basic question:
secondString = "\(firstString)\(secondString)"
or
secondString = firstString + secondString
Here is a way to insert string at the beginning "without resetting" per your comment (first at front of second):
let range = second.startIndex..<second.startIndex
second.replaceRange(range, with: first)
Re. your "more detail" question:
var fullString: String
if second == "00" {
fullString = third + fourth
} else if first == "00" {
fullString = second + third + fourth
} else {
fullString = first + second + third + fourth
}
From the Apple documentation:
String values can be added together (or concatenated) with the addition operator (+) to create a new String value:
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome now equals "hello there"
You can also append a String value to an existing String variable with the addition assignment operator (+=):
var instruction = "look over"
instruction += string2
// instruction now equals "look over there"
You can append a Character value to a String variable with the String type’s append() method:
let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// welcome now equals "hello there!"
So you are pretty much free to add these in any way shape or form.
Which includes
secondstring += firststring
Edit to accommodate the new information:
Strings in Swift are mutable which means you can always add to a string in-place without recreating any objects.
Something like (pseudo-code)
if(second != "00")
{
fullstring = second + fullstring
//only do something with first if second != 00
if(first != "00")
{
fullstring = first + fullstring
}
}
Related
Sorry,I'm new of swift. I want to calculate the target char in string.But I don't know how to do.Have any good suggestion to me?Thanks.
let string = "hello\nNice to meet you.\nMy name is Leo.\n" //I want to get 3
If you simply want a count of newline characters then you can use a filter on the string's characters:
let string = "hello\nNice to meet you.\nMy name is Leo.\n"
let count = string.characters.filter { $0 == "\n" }.count
print(count)
This outputs 3 as expected.
An alternative is to split the lines with the components(separatedBy method:
let string = "hello\nNice to meet you.\nMy name is Leo.\n"
let lineCounter = string.components(separatedBy: "\n").count - 1
or more versatile to consider all kinds of newline characters
let lineCounter = string.components(separatedBy: CharacterSet.newlines).count - 1
Due to the trailing newline character the result is 4. To ignore a trailing new line you have to decrement the result.
I have a id whose format is 1223-3939-ABC.1 and I would like to retrieve the last value i.e. 1 and increment it so now it looks like 1223-3939-ABC.2. But its possible that "1" is not there so in that case, I would like to append ".1"
I am trying to achieve this in Swift and here is my code:
var deviceId: String = "1234-ASCD-SCSDS.1"
if (deviceId != "") {
var id: [String] = deviceId.components(separatedBy: ".")
if let incrementedId: String = id.capacity > 1 ? deviceId.components(separatedBy: ".")[1] : "" {
if (incrementedId == "") {
//should append to id
var firstEle = deviceId.components(separatedBy: ".")[0]
firstEle.append(".")
firstEle.append("1")
deviceId = firstEle
} else {
// retrieve that id, convert to int, increment id, convert back to string and replace the old id with new id
let newId: Int = Int(deviceId.components(separatedBy: ".")[1])! + 1
deviceId = deviceId.replacingOccurrences(of: ".\\d", with: ".\(newId)", options: .regularExpression)
}
}
}
Not sure what I'm doing wrong?
Your regular expression for replacing is .\\d where . is actually any symbol. Replace it with \\.\\d and it will operate as expected.
You are referencing capacity but you need to reference count to understand an amount of components.
Based on documentation:
Capacity – the total number of elements that the array can contain without
allocating new storage.
There are several problems, such as
Wrong usage of capacity (as already said by Nikita),
Your code assumes that there is only a single dot, so that id
has exactly two elements.
Your code will crash if the dot is not followed by an integer.
The main problem is that
deviceId = deviceId.replacingOccurrences(of: ".\\d", with: ".\(newId)", options: .regularExpression)
replaces all occurrences of an arbitrary character followed by
any digit with ".\(newId)". It should probably be
deviceId = id[0] + ".\(newId)"
instead.
But the entire problem can be solved much easier:
Find the last occurrence of a dot.
Check if the part of the string following the dot can be converted to an integer.
If yes, replace that part by the increased integer, otherwise append .1
Both checks can be achieved with conditional binding, so that the
if-block is only executed if the device id already has a trailing
number:
var deviceId = "1234-ASCD-SCSDS.1"
if let pos = deviceId.range(of: ".", options: .backwards),
let id = Int(deviceId.substring(from: pos.upperBound)) {
deviceId = deviceId.substring(to: pos.upperBound) + String(id + 1)
} else {
deviceId = deviceId + ".1"
}
print(deviceId) // 1234-ASCD-SCSDS.2
I've been studying for a coding exam by doing the HackerRank test cases, for the most part I've been doing well, but I get hung up on some easy cases and you all help me when I can't see the solution. I'm working on this problem:
https://www.hackerrank.com/challenges/ctci-ransom-note
A kidnapper wrote a ransom note but is worried it will be traced back to him. He found a magazine and wants to know if he can cut out whole words from it and use them to create an untraceable replica of his ransom note. The words in his note are case-sensitive and he must use whole words available in the magazine, meaning he cannot use substrings or concatenation to create the words he needs.
Given the words in the magazine and the words in the ransom note, print Yes if he can replicate his ransom note exactly using whole words from the magazine; otherwise, print No.
Input Format
The first line contains two space-separated integers describing the respective values of (the number of words in the magazine) and (the number of words in the ransom note).
The second line contains space-separated strings denoting the words present in the magazine.
The third line contains space-separated strings denoting the words present in the ransom note.
Each word consists of English alphabetic letters (i.e., to and to ).
The words in the note and magazine are case-sensitive.
Output Format
Print Yes if he can use the magazine to create an untraceable replica of his ransom note; otherwise, print No.
Sample Input
6 4
give me one grand today night
give one grand today
Sample Output
Yes
Explanation
All four words needed to write an untraceable replica of the ransom note are present in the magazine, so we print Yes as our answer.
And here is my solution:
import Foundation
func main() -> String {
let v = readLine()!.components(separatedBy: " ").map{Int($0)!}
var a = [String](); var b = [String]()
if v[0] < v[1] { return "No"}
for i in 0 ..< 2 {
if i == 0 {
a = (readLine()!).components(separatedBy: " ")
} else { b = (readLine()!).components(separatedBy: " ") }
}
// Get list of elements that intersect in each array
let filtered = Set(a).intersection(Set(b))
// Map set to set of Boolean where true means set a has enough words to satisfy set b's needs
let checkB = filtered.map{ word in reduceSet(b, word: word) <= reduceSet(a, word: word) }
// If mapped set does not contain false, answer is Yes, else No
return !checkB.contains(false) ? "Yes" : "No"
}
func reduceSet(_ a: [String], word: String) -> Int {
return (a.reduce(0){ $0 + ($1 == word ? 1 : 0)})
}
print(main())
I always time out on three of the 20 test-cases with this solution. So the solution seems to solve all the test cases, but not within their required time constraints. These are great practice, but it's so extremely frustrating when you get stuck like this.
I should note that I use Sets and the Set(a).intersection(Set(b)) because when I tried mapping an array of Strings, half the test-cases timed out.
Any cleaner, or more efficient solutions will be greatly appreciated! Thank you!
Thanks to #Alexander - I was able to solve this issue using NSCountedSet instead of my custom reduce method. It's much cleaner and more efficient. Here is the solution:
import Foundation
func main() -> String {
let v = readLine()!.components(separatedBy: " ").map{Int($0)!}
var a = [String](); var b = [String]()
if v[0] < v[1] { return "No"}
for i in 0 ..< 2 {
if i == 0 {
a = (readLine()!).components(separatedBy: " ")
} else { b = (readLine()!).components(separatedBy: " ") }
}
let countA = NSCountedSet(array: a)
let countB = NSCountedSet(array: b)
let intersect = Set(a).intersection(Set(b))
let check = intersect.map{ countB.count(for: $0) <= countA.count(for: $0) }
return !check.contains(false) ? "Yes" : "No"
}
print(main())
Many thanks!
I took the leisure of making some improvements on your code. I put comments to explain the changes:
import Foundation
func main() -> String {
// Give more meaningful variable names
let firstLine = readLine()!.components(separatedBy: " ").map{Int($0)!}
let (magazineWordCount, ransomNoteWordCount) = (firstLine[0], firstLine[1])
// a guard reads more like an assertion, stating the affirmative, as opposed to denying the negation.
// it also
guard magazineWordCount > ransomNoteWordCount else { return "No" }
// Don't use a for loop if it only does 2 iterations, which are themselves hardcoded in.
// Just write the statements in order.
let magazineWords = readLine()!.components(separatedBy: " ")
let ransomNoteWords = readLine()!.components(separatedBy: " ") //You don't need ( ) around readLine()!
let magazineWordCounts = NSCountedSet(array: magazineWords)
let ransomNoteWordCounts = NSCountedSet(array: ransomNoteWords)
// intersect is a verb. you're looking for the noun, "intersection"
// let intersection = Set(a).intersection(Set(b))
// let check = intersect.map{ countB.count(for: $0) <= countA.count(for: $0) }
// You don't actually care for the intersection of the two sets.
// You only need to worry about exactly the set of words that
// exists in the ransom note. Just check them directly.
let hasWordWithShortage = ransomNoteWordCounts.contains(where: { word in
magazineWordCounts.count(for: word) < ransomNoteWordCounts.count(for: word)
})
// Don't negate the condition of a conditional expression. Just flip the order of the last 2 operands.
return hasWordWithShortage ? "No" : "Yes"
}
print(main())
with the comments removed:
import Foundation
func main() -> String {
let firstLine = readLine()!.components(separatedBy: " ").map{Int($0)!}
let (magazineWordCount, ransomNoteWordCount) = (firstLine[0], firstLine[1])
guard magazineWordCount > ransomNoteWordCount else { return "No" }
let magazineWords = readLine()!.components(separatedBy: " ")
let ransomNoteWords = readLine()!.components(separatedBy: " ")
let magazineWordCounts = NSCountedSet(array: magazineWords)
let ransomNoteWordCounts = NSCountedSet(array: ransomNoteWords)
let hasWordWithShortage = ransomNoteWordCounts.contains{ word in
magazineWordCounts.count(for: word) < ransomNoteWordCounts.count(for: word)
}
return hasWordWithShortage ? "No" : "Yes"
}
print(main())
It's simpler, and much easier to follow. :)
I've created a function that generates a RegularExpression in Swift 3.0. I'm close to what I want, but the backslash is causing me a lot of trouble.
I've looked at Swift Documentation and I thought changing the "\" to \u{005C} or u{005C} would resolve the issue, but it doesn't.
Here's the array I'm feeding my regex generation function:
var letterArray = ["a","","a","","","","","","",""]
Here's the relevant portion of my method:
var outputString = String()
// getMinimumWordLength returns 3
let minimumWordLength = getMinimumWordLength(letterArray: letterArray)
// for the array above, maximumWordLength returns 10
let maximumWordLength = letterArray.count
var index = 0
for letter in letterArray {
if index < minimumWordLength {
if letter as! String != "" {
outputString = outputString + letter.lowercased
} else {
// this puts an extra \ in my regex
outputString = outputString + "\\w" // first \ is an escape character, 2nd one gets read
// this puts an extra backslash in, too
// outputString = outputString + "\u{005C}w"
}
}
index += 1
}
outputString = outputString + ("{\(minimumWordLength),\(maximumWordLength)}$/")
return outputString
My desired output is:
a\wa{3,10}$/
My actual output is:
a\\wa{3,10}$/
If anyone has suggestions what I'm fouling up, I welcome them. Thank you for reading.
When string is printed in debugger, escape character will be displayed. When it is displayed for user, it will not.
For example:
I want to get the text/word by user and if this word's last character is "a" I want to change this "a" to "b"...How should i have to write this code?
let getText = txtWord.text
if
......
You need to check if the last char is "a".
If so just drop the last char and append the new one.
var text = txtWord.text
if text.characters.last == "a" {
text = String(text.characters.dropLast()) + "b"
}
swift 4:
let abc:String = txtWord.text
var newABC:String!
if abc.suffix(1) == 'a'{
newABC = abc + "b"
print("Done")
}