1

In Javascript, Node.js I can generate with https://www.npmjs.com/package/uuid package a 15 digit length "random" string. Is it possible it with Swift?

Like this: 802128100247740

const uuidv4 = require("uuid/v4");
tempUserUuid = uuidv4();
adiga
  • 34,372
  • 9
  • 61
  • 83
János
  • 32,867
  • 38
  • 193
  • 353

3 Answers3

9

Swift 5.0 introduced major improvements in dealing with random values and elements. The following code will help you

func randomString(length: Int) -> String {
  let letters = "0123456789"
  return String((0..<length).map{ _ in letters.randomElement()! })
}

label.text = randomString(length: 15)
Deep Kakkar
  • 5,831
  • 4
  • 39
  • 75
1

The other answers generate a random number multiple times, but you only need to do it once.

import Foundation

extension String {
  /// A leading-zero-padded padded random number.
  /// - Returns: nil if digitCount is too big for `UInt` (You get 19 or fewer!)
  static func randomNumber(digitCount: Int) -> Self? {
    let digitCountDouble = Double(digitCount)

    guard digitCountDouble < log10( Double(UInt.max) ) else {
      return nil
    }

    let formatter = NumberFormatter()
    formatter.minimumIntegerDigits = digitCount
    let upperBound = pow(10, digitCountDouble)
    return formatter.string(
      for: UInt.random( in: 0..<UInt(upperBound) )
    )!
  }
}
0
func randomString(length: Int) -> String {
    return (0..<length).map { _ in String(Int.random(in: 0...9)) }.joined()
}

func randomStringBuffer(length: Int) -> String {
    var buffer = ""
    (0..<length).forEach { _ in buffer += String(Int.random(in: 0...9)) }
    return buffer
}

print(randomString(length: 15))
print(randomStringBuffer(length: 15))

first is compact, but second is more efficient, but in this situation (generating only 15 digits string) it doesn't matter, I think

UPD I made a test, and it says that I was wrong. Seems first approach, with joined() is better

let a = Date().timeIntervalSince1970
print(a)
let g = randomString(length: 10000)
let b = Date().timeIntervalSince1970
print(b)
print(b - a)



let c = Date().timeIntervalSince1970
print(c)
let f = randomStringBuffer(length: 10000)
let d = Date().timeIntervalSince1970
print(d)
print(d - c)
1583933185.788064
1583933185.9271421
0.13907814025878906 // joined() version
1583933185.927207
1583933186.2418242
0.3146171569824219 // buffer version

UPD 2 Also made a public gist also with @deep-kakkar function. As I can see, "joined()" method made it most efficient

Alexey Lysenko
  • 1,890
  • 2
  • 12
  • 28
  • Why do you believe the second is more efficient? (It might be, but it's not obvious, and I wouldn't particularly expect it to be.) – Rob Napier Mar 11 '20 at 13:20
  • @RobNapier thanks for your question. I was thinking this because of how I thought `joined()` worked. But it seems, that it's work is not so inefficient as I was thinking. I made a test, and it turned out the opposite: `let a = Date().timeIntervalSince1970 let g = randomString(length: 10000) let b = Date().timeIntervalSince1970 print(b - a) let c = Date().timeIntervalSince1970 let f = randomStringBuffer(length: 10000) let d = Date().timeIntervalSince1970 print(d - c)` `0.13907814025878906. 0.3146171569824219` It seems `joined()` approach is better – Alexey Lysenko Mar 11 '20 at 13:29
  • 1
    `.map` is typically somewhat more efficient than a `+=` loop because it reserves all required memory in one allocation. `+=` may have to perform several memory reallocations, which may require significant copying depending on the state of memory fragmentation. `.joined` on `[String]` is implemented similarly, with a call to `reserveCapacity`. – Rob Napier Mar 11 '20 at 13:38
  • 2
    Also, be careful how you're testing these. Unless you're profiling in Release, the results are meaningless. I'm seeing them all very similar even in Debug, and nearly identical in Release. If the goal is performance, the fastest solution I've been able to build so far is: `String(data: Data((0.. – Rob Napier Mar 11 '20 at 14:35
  • 1
    (Testing performance against the random number generator is also always a bit tricky, since it can become the bottleneck and doesn't have consistent performance. I prefer the `.measure` tool in XCTestCase, since it averages many runs to smooth that out.) – Rob Napier Mar 11 '20 at 14:39