6
\$\begingroup\$

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?

asked May 13, 2023 at 14:05
\$\endgroup\$
3
  • 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\$ Commented May 13, 2023 at 14:31
  • \$\begingroup\$ @morbusg Great idea. Thanks. \$\endgroup\$ Commented May 14, 2023 at 4:51
  • \$\begingroup\$ @morbusg Works perfectly fine. I tried it out. \$\endgroup\$ Commented May 14, 2023 at 4:58

1 Answer 1

6
\$\begingroup\$

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 Characters 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 Sequences.

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
}
answered May 13, 2023 at 16:54
\$\endgroup\$
2
  • \$\begingroup\$ Addendum: There is a trivial case where the length of the string is greater than the considered alphabet size \$\endgroup\$ Commented 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\$ Commented May 15, 2023 at 14:12

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.