How to create a function which measures time performance of algorithms? - swift

If I want to evaluate time performance of a few algos using Date() or Dispatch() how can I create a function that does this?
For example this binary search algo. How can I pass it as a closure parameter and have the closure do all of the time performance measuring using any of the Swift time keeping methods below? Please answer with an example of a closure. Thanks.
let startingPoint = Date()
let startingPoint = Dispatch().now
func binarySearchForValue(searchValue: Int, array: [Int]) -> Bool {
var leftIndex = 0
var rightIndex = array.count - 1
while leftIndex <= rightIndex {
let middleIndex = (leftIndex + rightIndex) / 2
let middleValue = array[middleIndex]
if middleValue == searchValue {
return true
}
if searchValue < middleValue {
rightIndex = middleIndex - 1
}
if searchValue > middleValue {
leftIndex = middleIndex + 1
}
}
return false
}

Since you may want to measure different functions, it probably makes sense to capture the arguments for the function in the closure instead of including their types in the signature. But I did use a generic type for the return value. I hope that this is what you're after:
func measure<R>(_ label: String, operation: () -> R) -> R {
let start = DispatchTime.now()
let result = operation()
let end = DispatchTime.now()
let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds
let timeInterval = Double(nanoTime) / 1_000_000_000
print(String(format: "%#: %.9f s", label, timeInterval))
return result
}
Here's how you use it:
let result = measure("search") { binarySearchForValue(searchValue: 3, array: [1, 3, 8]) }
print(result) // that's the result of the function that was measured, not the measurement
measure("some function") { functionWithoutReturnValue() }
If the function has no return value, R will be (), so that should work too. Just don't assign the result to anything (see the example above). If you want to do something with the measurement other than printing it to the console, you can do that, too. But you didn't specify that in your question, so I went with print.

Not sure what exactly you are after here and this solution below will only fit one specific function signature to test
func testBench(search: Int, array: [Int], testCase test: (Int, [Int]) -> Bool) {
let start = DispatchTime.now()
test(search, array)
let end = DispatchTime.now()
print("\(start) - \(end)")
}
called like this
testBench(search: 3, array: [6,7,5,3]) {binarySearchForValue(searchValue: $0, array: $1)}

You should use XCTest to measure the performance ... It gives you proper stats for your method in terms of performance
i.e.
func testMyCodesPerformance() {
measureBlock {
someClass.doSomethingFancy()
}
}
You can do lot more using XCTest measureBlock for performance testing

Related

How to create 15 digit length random string in Swift? [duplicate]

This question already has answers here:
Random Password Generator Swift 3?
(3 answers)
Closed 2 years ago.
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();
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)
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) )
)!
}
}
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

Sum integers from a key value until there is one-digit

I need a function that both reduces integers to a single digit and accepts strings. Variants using reduce would also be appreciated.
let dict: [Character:Int] = ["a": 1, "j":1, "s":1, "b":2, "k":2, "t":2, "c":3, "l":3, "u":3, "d":4, "m":4, "v":4, "e":5, "n":5, "w":5, "f":6, "o":6, "x":6, "g":7, "p":7, "y":7, "h":8, "q":8, "z":8, "i":9, "r":9]
This function accepts strings and reduces by summing, but does not reduce to a single digit.
func f1(_ str: String) -> Int {
return str.reduce(0) { $0 + (dict[$1] ?? 0) }
}
f1("lighthouse") //52
This function reduces to a single digit but does not accepts strings.
func f2(_ n: Int) -> Int {
return (1 + ((n-1) % 9))
}
f2(52) //7
You just need to combine your both methods in the return statement:
return 1 + (str.reduce(0) {$0 + (dict[$1] ?? 0)} - 1) % 9
Here is a function that converts a string into a single digit Int.
Input: "9l231ffi1j"
func f1(_ str: String) -> Int {
return str.reduce(0) { $0 + ((Int(String($1)) ?? dict[$1]) ?? 0) }
}
func f3(_ input : String) -> Int {
return f2(f1(input))
}
f3("lighthouse") //7
f3("9l231ffi1j") //5
Thanks to Leo's answer in this question and Martin's answer in my other related [question] I was able to produce a standard version using Swift's for in loop without shorthand {$0 $1} and reduce().
let n = "lighthouse"
var nScore = 0
for i in n.indices {
let curChar = n[i]
let curVal = dict[curChar, default: 0]
nScore = 1 + (nScore + curVal - 1) % 9
}
nScore //7

How to convert Data of Int16 audio samples to array of float audio samples

I'm currently working with audio samples.
I get them from AVAssetReader and have a CMSampleBuffer with something like this:
guard let sampleBuffer = readerOutput.copyNextSampleBuffer() else {
guard reader.status == .completed else { return nil }
// Completed
// samples is an array of Int16
let samples = sampleData.withUnsafeBytes {
Array(UnsafeBufferPointer<Int16>(
start: $0, count: sampleData.count / MemoryLayout<Int16>.size))
}
// The only way I found to convert [Int16] -> [Float]...
return samples.map { Float($0) / Float(Int16.max)}
}
guard let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) else {
return nil
}
let length = CMBlockBufferGetDataLength(blockBuffer)
let sampleBytes = UnsafeMutablePointer<UInt8>.allocate(capacity: length)
CMBlockBufferCopyDataBytes(blockBuffer, 0, length, sampleBytes)
sampleData.append(sampleBytes, count: length)
}
As you can see the only I found to convert [Int16] -> [Float] issamples.map { Float($0) / Float(Int16.max) but by doing this my processing time is increasing. Does it exist an other way to cast a pointer of Int16 to a pointer of Float?
"Casting" or "rebinding" a pointer only changes the way how memory is
interpreted. You want to compute floating point values from integers,
the new values have a different memory representation (and also a different
size).
Therefore you somehow have to iterate over all input values
and compute the new values. What you can do is to omit the Array
creation:
let samples = sampleData.withUnsafeBytes {
UnsafeBufferPointer<Int16>(start: $0, count: sampleData.count / MemoryLayout<Int16>.size)
}
return samples.map { Float($0) / Float(Int16.max) }
Another option would be to use the vDSP functions from the
Accelerate framework:
import Accelerate
// ...
let numSamples = sampleData.count / MemoryLayout<Int16>.size
var factor = Float(Int16.max)
var floats: [Float] = Array(repeating: 0.0, count: numSamples)
// Int16 array to Float array:
sampleData.withUnsafeBytes {
vDSP_vflt16($0, 1, &floats, 1, vDSP_Length(numSamples))
}
// Scaling:
vDSP_vsdiv(&floats, 1, &factor, &floats, 1, vDSP_Length(numSamples))
I don't know if that is faster, you'll have to check.
(Update: It is faster, as ColGraff demonstrated in his answer.)
An explicit loop is also much faster than using map:
let factor = Float(Int16.max)
let samples = sampleData.withUnsafeBytes {
UnsafeBufferPointer<Int16>(start: $0, count: sampleData.count / MemoryLayout<Int16>.size)
}
var floats: [Float] = Array(repeating: 0.0, count: samples.count)
for i in 0..<samples.count {
floats[i] = Float(samples[i]) / factor
}
return floats
An additional option in your case might be to use CMBlockBufferGetDataPointer() instead of CMBlockBufferCopyDataBytes()
into allocated memory.
You can do considerably better if you use the Accelerate Framework for the conversion:
import Accelerate
// Set up random [Int]
var randomInt = [Int16]()
randomInt.reserveCapacity(10000)
for _ in 0..<randomInt.capacity {
let value = Int16(Int32(arc4random_uniform(UInt32(UInt16.max))) - Int32(UInt16.max / 2))
randomInt.append(value)
}
// Time elapsed helper: https://stackoverflow.com/a/25022722/887210
func printTimeElapsedWhenRunningCode(title:String, operation:()->()) {
let startTime = CFAbsoluteTimeGetCurrent()
operation()
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("Time elapsed for \(title): \(timeElapsed) s.")
}
// Testing
printTimeElapsedWhenRunningCode(title: "vDSP") {
var randomFloat = [Float](repeating: 0, count: randomInt.capacity)
vDSP_vflt16(randomInt, 1, &randomFloat, 1, vDSP_Length(randomInt.capacity))
}
printTimeElapsedWhenRunningCode(title: "map") {
randomInt.map { Float($0) }
}
// Results
//
// Time elapsed for vDSP : 0.000429034233093262 s.
// Time elapsed for flatMap: 0.00233501195907593 s.
It's an improvement of about 5 times faster.
(Edit: Added some changes suggested by Martin R)
#MartinR and #ColGraff gave really good answers, and thank you for everybody and the fast replies.
however I found an easier way to do that without any computation. AVAssetReaderAudioMixOutput requires an audio settings dictionary. Inside we can set the key AVLinearPCMIsFloatKey: true. This way I will read my data like this
let samples = sampleData.withUnsafeBytes {
UnsafeBufferPointer<Float>(start: $0,
count: sampleData.count / MemoryLayout<Float>.size)
}
for: Xcode 8.3.3 • Swift 3.1
extension Collection where Iterator.Element == Int16 {
var floatArray: [Float] {
return flatMap{ Float($0) }
}
}
usage:
let int16Array: [Int16] = [1, 2, 3 ,4]
let floatArray = int16Array.floatArray

Generating random numbers with Swift

I need to generate a random number.
It appears the arc4random function no longer exists as well as the arc4random_uniform function.
The options I have are arc4random_stir(), arc4random_buf(UnsafeMutablePointer<Void>, Int), and arc4random_addrandom(UnsafeMutablePointer<UInt8>, Int32).
I can't find any docs on the functions and no comments in the header files give hints.
let randomIntFrom0To10 = Int.random(in: 1..<10)
let randomFloat = Float.random(in: 0..<1)
// if you want to get a random element in an array
let greetings = ["hey", "hi", "hello", "hola"]
greetings.randomElement()
You could try as well:
let diceRoll = Int(arc4random_uniform(UInt32(6)))
I had to add "UInt32" to make it work.
Just call this function and provide minimum and maximum range of number and you will get a random number.
eg.like randomNumber(MIN: 0, MAX: 10) and You will get number between 0 to 9.
func randomNumber(MIN: Int, MAX: Int)-> Int{
return Int(arc4random_uniform(UInt32(MAX-MIN)) + UInt32(MIN));
}
Note:- You will always get output an Integer number.
After some investigation I wrote this:
import Foundation
struct Math {
private static var seeded = false
static func randomFractional() -> CGFloat {
if !Math.seeded {
let time = Int(NSDate().timeIntervalSinceReferenceDate)
srand48(time)
Math.seeded = true
}
return CGFloat(drand48())
}
}
Now you can just do Math.randomFraction() to get random numbers [0..1[ without having to remember seeding first. Hope this helps someone :o)
Update with swift 4.2 :
let randomInt = Int.random(in: 1..<5)
let randomFloat = Float.random(in: 1..<10)
let randomDouble = Double.random(in: 1...100)
let randomCGFloat = CGFloat.random(in: 1...1000)
Another option is to use the xorshift128plus algorithm:
func xorshift128plus(seed0 : UInt64, _ seed1 : UInt64) -> () -> UInt64 {
var state0 : UInt64 = seed0
var state1 : UInt64 = seed1
if state0 == 0 && state1 == 0 {
state0 = 1 // both state variables cannot be 0
}
func rand() -> UInt64 {
var s1 : UInt64 = state0
let s0 : UInt64 = state1
state0 = s0
s1 ^= s1 << 23
s1 ^= s1 >> 17
s1 ^= s0
s1 ^= s0 >> 26
state1 = s1
return UInt64.addWithOverflow(state0, state1).0
}
return rand
}
This algorithm has a period of 2^128 - 1 and passes all the tests of the BigCrush test suite. Note that while this is a high-quality pseudo-random number generator with a long period, it is not a cryptographically secure random number generator.
You could seed it from the current time or any other random source of entropy. For example, if you had a function called urand64() that read a UInt64 from /dev/urandom, you could use it like this:
let rand = xorshift128plus(urand64(), urand64())
for _ in 1...10 {
print(rand())
}
let MAX : UInt32 = 9
let MIN : UInt32 = 1
func randomNumber()
{
var random_number = Int(arc4random_uniform(MAX) + MIN)
print ("random = ", random_number);
}
In Swift 3 :
It will generate random number between 0 to limit
let limit : UInt32 = 6
print("Random Number : \(arc4random_uniform(limit))")
My implementation as an Int extension. Will generate random numbers in range from..<to
public extension Int {
static func random(from: Int, to: Int) -> Int {
guard to > from else {
assertionFailure("Can not generate negative random numbers")
return 0
}
return Int(arc4random_uniform(UInt32(to - from)) + UInt32(from))
}
}
This is how I get a random number between 2 int's!
func randomNumber(MIN: Int, MAX: Int)-> Int{
var list : [Int] = []
for i in MIN...MAX {
list.append(i)
}
return list[Int(arc4random_uniform(UInt32(list.count)))]
}
usage:
print("My Random Number is: \(randomNumber(MIN:-10,MAX:10))")
Another option is to use GKMersenneTwisterRandomSource from GameKit. The docs say:
A deterministic pseudo-random source that generates random numbers
based on a mersenne twister algorithm. This is a deterministic random
source suitable for creating reliable gameplay mechanics. It is
slightly slower than an Arc4 source, but more random, in that it has a
longer period until repeating sequences. While deterministic, this is
not a cryptographic random source. It is however suitable for
obfuscation of gameplay data.
import GameKit
let minValue = 0
let maxValue = 100
var randomDistribution: GKRandomDistribution?
let randomSource = GKMersenneTwisterRandomSource()
randomDistribution = GKRandomDistribution(randomSource: randomSource, lowestValue: minValue, highestValue: maxValue)
let number = randomDistribution?.nextInt() ?? 0
print(number)
Example taken from Apple's sample code: https://github.com/carekit-apple/CareKit/blob/master/CareKitPrototypingTool/OCKPrototyper/CareKitPatient/RandomNumberGeneratorHelper.swift
I'm late to the party 🤩🎉
Using a function that allows you to change the size of the array and the range selection on the fly is the most versatile method. You can also use map so it's very concise. I use it in all of my performance testing/bench marking.
elements is the number of items in the array
only including numbers from 0...max
func randArr(_ elements: Int, _ max: Int) -> [Int] {
return (0..<elements).map{ _ in Int.random(in: 0...max) }
}
Code Sense / Placeholders look like this.
randArr(elements: Int, max: Int)
10 elements in my array ranging from 0 to 1000.
randArr(10, 1000) // [554, 8, 54, 87, 10, 33, 349, 888, 2, 77]
you can use this in specific rate:
let die = [1, 2, 3, 4, 5, 6]
let firstRoll = die[Int(arc4random_uniform(UInt32(die.count)))]
let secondRoll = die[Int(arc4random_uniform(UInt32(die.count)))]
Lets Code with Swift for the random number or random string :)
let quotes: NSArray = ["R", "A", "N", "D", "O", "M"]
let randomNumber = arc4random_uniform(UInt32(quotes.count))
let quoteString = quotes[Int(randomNumber)]
print(quoteString)
it will give you output randomly.
Don't forget that some numbers will repeat! so you need to do something like....
my totalQuestions was 47.
func getRandomNumbers(totalQuestions:Int) -> NSMutableArray
{
var arrayOfRandomQuestions: [Int] = []
print("arraySizeRequired = 40")
print("totalQuestions = \(totalQuestions)")
//This will output a 40 random numbers between 0 and totalQuestions (47)
while arrayOfRandomQuestions.count < 40
{
let limit: UInt32 = UInt32(totalQuestions)
let theRandomNumber = (Int(arc4random_uniform(limit)))
if arrayOfRandomQuestions.contains(theRandomNumber)
{
print("ping")
}
else
{
//item not found
arrayOfRandomQuestions.append(theRandomNumber)
}
}
print("Random Number set = \(arrayOfRandomQuestions)")
print("arrayOutputCount = \(arrayOfRandomQuestions.count)")
return arrayOfRandomQuestions as! NSMutableArray
}
look, i had the same problem but i insert
the function as a global variable
as
var RNumber = Int(arc4random_uniform(9)+1)
func GetCase(){
your code
}
obviously this is not efficent, so then i just copy and paste the code into the function so it could be reusable, then xcode suggest me to set the var as constant so my code were
func GetCase() {
let RNumber = Int(arc4random_uniform(9)+1)
if categoria == 1 {
}
}
well thats a part of my code so xcode tell me something of inmutable and initialization but, it build the app anyway and that advice simply dissapear
hope it helps

Recursion over a Swift Sliceable

I feel that I must be missing something obvious. Decomposing a list into the head and tail and then recursing over the tail is a standard functional programming technique, yet I'm struggling to do this for Sliceable types in Swift.
I have a recursive function that follows this pattern:
func recurseArray(arr: [Int]) -> [Int] {
guard let first = arr.first else {
return []
}
let rest = recurseArray(Array(dropFirst(arr)))
let next = rest.first ?? 0
return [first + next] + rest
}
Obviously the real code does a lot more than add each number to the next.
Note the call to Array(dropFirst(seq)). Converting to an Array is required since dropFirst actually returns an ArraySlice, and an ArraySlice isn't a Sliceable, so I can't pass it to my function.
I'm not sure what sort of optimization the compiler is capable of here, but it seems to me that creating a new array from a SubSlice unnecessarily won't be optimal. Is there a solution to this?
Furthermore, what I'd really like to do is create a version of this function that can take any Sliceable type:
func recurseSeq<T: Sliceable where T.Generator.Element == Int>(list: T) -> [Int] {
guard let first = list.first else {
return []
}
let rest = recurseSeq(dropFirst(list)) // <- Error - cannot invoke with argument type T.SubSlice
let next = rest.first ?? 0
return [first + next] + rest
}
This time I don't have a solution to the fact that I have a SubSlice. How can I achieve my goal?
It turns out that there is a generic solution. You need to add these generic requirements:
<
S : Sliceable where S.SubSlice : Sliceable,
S.SubSlice.Generator.Element == S.Generator.Element,
S.SubSlice.SubSlice == S.SubSlice
>
For the question posted, this gives:
func recurseSeq<
S : Sliceable where S.SubSlice : Sliceable,
S.SubSlice.Generator.Element == Int,
S.SubSlice.SubSlice == S.SubSlice,
S.Generator.Element == Int
>(list: S) -> [Int] {
guard let first = list.first else {
return []
}
let rest = recurseSeq(dropFirst(list))
let next = rest.first ?? 0
return [first + next] + rest
}
Here's a useful generic reduce on any sliceable:
extension Sliceable where
SubSlice : Sliceable,
SubSlice.Generator.Element == Generator.Element,
SubSlice.SubSlice == SubSlice {
func recReduce(combine: (Generator.Element, Generator.Element) -> Generator.Element) -> Generator.Element? {
return self.first.map {
head in
dropFirst(self)
.recReduce(combine)
.map {combine(head, $0)}
?? head
}
}
}
[1, 2, 3].recReduce(+) // 6
I can't take credit for this, the solution was posted on the Apple Development Forums.
It's a shame that the generic requirements are so involved for such a a basic operation - it's hardly intuitive! But I'm glad to have a solution...
Actually ArraySlice is Sliceable, so you can recurse on
ArraySlice<Int>:
func recurseArray(arr: ArraySlice<Int>) -> [Int] {
guard let first = arr.first else {
return []
}
let rest = recurseArray(dropFirst(arr))
let next = rest.first ?? 0
return [first + next] + rest
}
with a wrapper function which is called only once at the top level:
func recurseArray(arr: [Int]) -> [Int] {
return recurseArray(arr[arr.startIndex ..< arr.endIndex])
}
I don't have a solution for your second more general problem.
The API docs for Sliceable state that SubSlice should be
Sliceable itself (which is the case for all known Sliceable
types).
I have therefore the feeling that it should be possible by requesting
that T.SubSlice is itself sliceable with the identical SubSlice
type, however this does not compile:
func recurseSeq<T: Sliceable where T.Generator.Element == Int,
T.SubSlice : Sliceable,
T.SubSlice.SubSlice == T.SubSlice>(list: T.SubSlice) -> [Int] {
guard let first = list.first else {
return []
}
let rest = recurseSeq(dropFirst(list) as T.SubSlice)
// error: cannot invoke 'recurseSeq' with an argument list of type '(T.SubSlice)'
let next = rest.first ?? 0
return [first + next] + rest
}
The compiler accepts that dropFirst(list) can be cast to T.SubSlice,
but refuses to call recurseSeq() on that value, which I do not
understand.
Alternatively, you can recurse on a GeneratorType:
func recurseGen<G: GeneratorType where G.Element == Int>(inout gen: G) -> [Int] {
guard let first = gen.next() else {
return []
}
let rest = recurseGen(&gen)
let next = rest.first ?? 0
return [first + next] + rest
}
with a wrapper that takes a SequenceType:
func recurseSeq<T: SequenceType where T.Generator.Element == Int>(list: T) -> [Int] {
var gen = list.generate()
return recurseGen(&gen)
}
Arrays and array slices all conform to SequenceType, so that should
work in all your cases.
Creating an array in every iteration doesn't seem like a good idea. I don't know if the compiler optimizes it somehow, but you could probably find a different solution.
For example, in this case, you could drop de recursion and use a for loop instead that modifies the array in place.
func recurseArray2(var a: [Int]) -> [Int] {
for var i = a.count-1; i > 0; i-- {
a[i-1] += a[i]
}
return a
}