I have an array of names that looks like the following. ["John Doe", "Mary Blog"]
What I want to do is process this array and return an array with the initials like the following.
["JD", "MB"]
I have already done this but my code is ugly and inefficient (nested loops). It's probably fine for a small array like in my example.
How can I process my array more efficiently?
let contacts = ["John Doe", "Mary Blog"]
var initalsArray: [String] = []
let names = contacts.map {$0}
for name in names {
var initals: String = ""
let fullname = name.components(separatedBy: " ")
for part in fullname {
if part.count > 0 {
initals = part[0]
}
}
initalsArray.append(initals)
}
CodePudding user response:
I did not compare the efficiency of this with the above answers but if you are dealing with names
, using PersonNameComponentsFormatter
will help you a lot. Check the documentation here.
In your case following code gives the required output.
let formatter = PersonNameComponentsFormatter()
let contacts = ["John Doe", "Mary Blog"]
var initalsArray: [String] = []
for contact in contacts {
if let name = formatter.personNameComponents(from: contact) {
formatter.style = .abbreviated
initalsArray.append(formatter.string(from: name))
}
}
output -> ["JD", "MB"]
CodePudding user response:
You must process all elements in the array.
For every element, you must detect the spaces and retrieve the next letter.
Then you must build up the output array with concatenated capitals.
So I really don't see how you could avoid a double loop.
Only if part.count > 0
is unnecessary.
Alternatively, you can scan the strings yourself to avoid generating the intermediate array fullname
.
You can probably also obtain the result by regex processing, but this would be a sledgehammer to crack nuts. Don't.
A possible implementation of the inner loop. (Sorry if this is invalid, I don't know Swift).
var space: Bool = true
for c in name {
if space && c != ' ' {
initials = c
}
space= c == ' '
}
Notice that the (optional) extra condition c != ' '
protects against double spaces.
CodePudding user response:
You can use map to remove some of your own looping
let contacts = ["John Doe", "Mary Blog"]
let result = contacts.map { $0.components(separatedBy: .whitespacesAndNewlines).map { String($0.prefix(1)) }.joined(separator: "") }
print(result)
I don't known if this is any quicker, maybe it gives Apple a chance to fro some optimisation that is hard to do
CodePudding user response:
Actually this answer though similar may be a bit quicker
let contacts = ["John Doe", "Mary Blog"]
let result = contacts.map { $0.components(separatedBy: .whitespacesAndNewlines).reduce("") { $0 String($1.prefix(1)) } }
print(result)
Instated of constructing inner arrays and then joining them I just added it to the string of previous first letters