5

According to Swift 5 docs, String has method randomElement() with complexity O(1) or O(*n*) depending on conformance to RandomAccessCollection protocol.

randomElement method description

Therefore, I am wondering how to make cases where randomElement() of String complexity will be O(1).

My string is just:

let letters = "abcdefghijklmnopqrstuvwxyz"

Questions:

  1. How do I check if my particular string conforms to RandomAccessCollection?
  2. How to create / remove conformance to RandomAccessCollection protocol from a string?
Oleksii Shnyra
  • 623
  • 1
  • 6
  • 24

2 Answers2

8

A string is never a random access collection. If that’s what you want, cast to an Array.

matt
  • 515,959
  • 87
  • 875
  • 1,141
3

randomElement is a requirement of the Collection protocol, as you can see here.

So String is merely conforming to Collection by implementing this method, and the documentation comment is just a copy-paste from the original one in Collection.

If you read the documentation comment in the context of Collection instead of String, it makes a lot more sense. It's saying that if self is also a RandomAccessCollection, then it's O(1), otherwise it's O(n).

String does not conform to RandomAccessCollection, as you can see here, so String.randomElement is O(n).

EDIT:

To check if something is a RandomAccessCollection of Character, you can't do it directly with is, because RandomAccessCollection has associated types. One way to do this is to define a function that accepts a constrained type parameter:

let letters = Array("abcdefghijklmnopqrstuvwxyz")
func f<T>(_ x: T) where T : RandomAccessCollection, T.Element == Character {}
f(letters) // if this compiles, then Array<Character> conforms to RandomAccessCollection and Element is Character
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • One could consider this a bug in the automatically generated documentation. The documentation of the protocol methods are verbatim copied into the documentation of all conforming types. (Even the given example in https://developer.apple.com/documentation/swift/string/2997145-randomelement is not about a random element in a string.) – Martin R May 26 '19 at 07:28
  • OK, I will treat documentation less seriously. Please, give an example of RandomAccessCollection of characters and how to verify that this collection conforms to RandomAccessCollection. – Oleksii Shnyra May 26 '19 at 07:32
  • `[Character]` is a `RandomAccessCollection`, since [`Array` conforms to `RandomAccessCollection`](https://developer.apple.com/documentation/swift/array#relationships) @OleksiiShnyra – Sweeper May 26 '19 at 07:34
  • @Sweeper I need to check it programmatically. Something like below, but working example. Any ideas? ```let letters = Array("abcdefghijklmnopqrstuvwxyz") if letters.self is RandomAccessCollection.Type { print("conforms") }``` – Oleksii Shnyra May 26 '19 at 07:42
  • @OleksiiShnyra: Only *types* can conform to a protocol, not *instances* of a type. – Martin R May 26 '19 at 07:44
  • @MartinR code works fine with ```if letters.self is Array { print("conforms") }``` but not sure how to make it with ```letters.self is RandomAccessCollection.Type``` – Oleksii Shnyra May 26 '19 at 07:51
  • @Sweeper thanks for edits, but I need a run-time check, simple true / false condition. – Oleksii Shnyra May 26 '19 at 07:58
  • 1
    I don't think this is possible. Refer to [this question](https://stackoverflow.com/questions/47230168/checking-conforms-protocol-with-associatedtype-in-swift). – Sweeper May 26 '19 at 08:06
  • Building on your idea @Sweeper, you can create two generic functions `isRandomAccessCollection` one with a type constraint to `RandomAccessCollection` that returns `true` and the other with no constraint that returns `false`. Then `isRandomAccessCollection("abc")` returns `false`, but `isRandomAccessCollection(Array("abc"))` returns `true`. – vacawama May 26 '19 at 10:12
  • @vacawama I interpreted a "runtime-check" as the OP having a variable of an unknown type (`Any`) and wants to check if it is a `RandomAccessCollection`. – Sweeper May 26 '19 at 10:14
  • Ah I see. My pair of functions is useful for just quickly exploring which types of objects are RandomAccessCollections ... strings - no, Array(string) - yes, dictionary - no, dictionary.keys - no, etc. – vacawama May 26 '19 at 10:24