The task is writing a function, which checks if a string contains only unique characters. Means: is each character is included only one time.
Here's the solution, I have developed:
func areAllLettersUnique(_ str: String) -> Bool {
let arr = str.split(separator: "")
for (i, chr) in arr.enumerated() {
if arr[i + 1..<arr.count].contains(chr) {
return false
}
}
return true
}
assert(areAllLettersUnique("No duplicates") == true, "Challenge 1.1 failed")
assert(areAllLettersUnique("abcdefghijklmnopqrstuvwxyz") == true, "Challenge 1.2 failed")
assert(areAllLettersUnique("AaBbCc") == true, "Challenge 1.3 failed")
assert(areAllLettersUnique("Hello, world") == false, "Challenge 1.4 failed")
print("All assertions successful")
It has passed the provided asserts and I think it works correct.
But: Is there a better, perhaps more "swifty" solution?
Can I expect my code to work correctly or are there flaws?
-
4\$\begingroup\$ Not familiar with swift, but generally if you make a Set from the string, and compare its length with the original strings length, you get the answer without (explicit) iteration. \$\endgroup\$morbusg– morbusg2023年05月13日 14:31:44 +00:00Commented May 13, 2023 at 14:31
-
\$\begingroup\$ @morbusg Great idea. Thanks. \$\endgroup\$michael.zech– michael.zech2023年05月14日 04:51:05 +00:00Commented May 14, 2023 at 4:51
-
\$\begingroup\$ @morbusg Works perfectly fine. I tried it out. \$\endgroup\$michael.zech– michael.zech2023年05月14日 04:58:11 +00:00Commented May 14, 2023 at 4:58
1 Answer 1
This
let arr = str.split(separator: "")
creates an array of one-element substrings of the original string. It is simpler to create an array of Character
s with
let arr = Array(str)
It might also be a bit more efficient to compare characters instead of substrings. Also this works not only for strings but for arbitrary Sequence
s.
if arr[i + 1..<arr.count].contains(chr)
can be simplified slightly using a RangeExpression, in this case ...
if arr[(i + 1)...].contains(chr)
The variable name arr
does not indicate what it contains, a better choice might be something like allCharacters
.
Your method is not very efficient, the complexity is \$ O(N^2) \$ where \$ N \$ is the length of the string.
One can use a Set
to store the distinct characters of the string. A very short and simple implementation would be
func areAllLettersUnique(_ str: String) -> Bool {
let allCharacters = Set(str)
return allCharacters.count == str.count
}
but this does not "short-circuit": The entire string is processed even if a duplicate character has been found.
But one can enumerate the characters and keep track of all characters seen to far:
func areAllLettersUnique(_ str: String) -> Bool {
var charactersSeenSoFar = Set<Character>()
for chr in str {
if charactersSeenSoFar.contains(chr) {
return false
}
charactersSeenSoFar.insert(chr)
}
return true
}
The insert
operation of a Set
returns a value which indicates whether the element was newly inserted or already present, so this can be further simplified to
func areAllLettersUnique(_ str: String) -> Bool {
var charactersSeenSoFar = Set<Character>()
for chr in str {
if !charactersSeenSoFar.insert(chr).inserted {
return false
}
}
return true
}
Finally note that this method can be made generic with minor changes, so that it can be used with arbitrary sequences of (hashable) elements
func areAllElementsUnique<C>(_ seq: C) -> Bool
where C: Sequence, C.Element: Hashable
{
var elementsSeenSoFar = Set<C.Element>()
for elem in seq {
if !elementsSeenSoFar.insert(elem).inserted {
return false
}
}
return true
}
-
\$\begingroup\$ Addendum: There is a trivial case where the length of the string is greater than the considered alphabet size \$\endgroup\$ielyamani– ielyamani2023年05月15日 14:01:42 +00:00Commented May 15, 2023 at 14:01
-
2\$\begingroup\$ @ielyamani: Sure, that might be useful in programming contests where a restriction on the alphabet it given, e.g. only latin characters. – For a general purpose routine that might not be relevant, a Swift
String
is a collection of "extended grapheme clusters" and the Unicode Standard contains 149,186 characters \$\endgroup\$Martin R– Martin R2023年05月15日 14:12:11 +00:00Commented May 15, 2023 at 14:12