Fix warning "C-style for Statement is deprecated" in Swift 3 - swift

I have update Xcode to 7.3 and now I have a warning to the function that I use to create random strings.
I have tried to change the for statement with for (i in 0 ..< len){...} however, the warning became an error.
How can I remove the warning?
static func randomStringWithLength (len : Int) -> NSString {
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let randomString : NSMutableString = NSMutableString(capacity: len)
for (var i=0; i < len; i += 1){ // warning
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
return randomString
}

C-style for loop has been deprecated in Swift 3. You can continue using it for a while, but they will certainly disappear in the future.
You can rewrite your loop to Swift's style:
for i in 0..<len {
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
Since you don't use i at all in the loop's body, you can replace it with:
for _ in 0..<len {
// do stuffs
}

This BLOG saved my life.
INCREMENTING
for i in 0 ..< len {
}
DECREMENTING
for i in (0 ..< len).reverse() {
}
NON-SEQUENTIAL INDEXING
Using where
for i in (0 ..< len) where i % 2 == 0 {
}
Using striding to or through
for i in 0.stride(to: len, by: 2) {
}

in Swift 3 it's been an error
some general replacement was posted and just add
For Swift 3 and need to change the "index"
for var index in stride(from: 0, to: 10, by: 1){}

I've had success with the following. You can use the for loop as follows - note that the for loop is inclusive so you may need to check that len is actually greater than 0:
for i in 0...len - 1 {
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
Or you can use this:
for i in 0 ..< len {
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
BTW it appears XCode 7.x does help you to get there but it's a two step process. First you have to change your increment operator from (say) i++ to i += 1 and then XCode warning helps you modify the loop.

Related

no response on stdout HackerRank Swift

Hello i practice on hackerRank using swift and now i have a problem. My code works great in swift playground, and return the expected result, but in HackerRank i have runtime error ~ no response on stdout ~ I've tried to reset code and refresh page. What could be the problem?
func diagonalDifference(arr: [[Int]]) -> Int {
// Write your code here
let rowNumber = arr[0][0]
var leftD = 0
var rightD = 0
for i in 1...rowNumber {
leftD += arr[i][i - 1]
}
var increasedNum = 0
for i in (1...rowNumber).reversed() {
rightD += arr[i][increasedNum]
increasedNum += 1
}
var absoluteDifference = leftD - rightD
if absoluteDifference < 0 {
absoluteDifference = absoluteDifference * -1
}
return absoluteDifference
}
Here is the challenge page:
https://www.hackerrank.com/challenges/diagonal-difference/problem
Your problem is a misunderstanding of what is passed to your diagonalDifference() function. The code which calls that function uses the first line of input to correctly size the array, but that value is not passed to your function in arr[0][0]. Instead, you should use arr.count to determine the dimensions of the array, then you should be indexing the array as 0..<arr.count.
To fix your code
change:
let rowNumber = arr[0][0]
to:
let rowNumber = arr.count
change:
leftD += arr[i][i - 1]
to:
leftD += arr[i][i]
And change both instances of
1...rowNumber
to:
0..<rowNumber
func diagonalDifference(arr: [[Int]]) -> Int {
var difference = 0
for i in 0..<arr.count {
difference += (arr[i][i] - arr[i][arr.count-1-i])
}
return Int(abs(difference))
}

Replacement for c style loop with modulo

Since C-style for statement is deprecated and will be removed in a future version of Swift, what is the best way to achieve the following:
for var i = startIndex; i != endIndex; i = (i + 1) % arrCount {
}
(I want to iterate the array, but start from somewhere at the middle and continue until I'll reach the index I started from)
Edit:
startIndex > endIndex
"while" should be the best:
var i = startIndex
while i != endIndex {
i = (i + 1) % arrCount
}
You can shift the original array pretty easily, see this example:
let array = [3,4,5,6,7]
let startIndex = 3
let endIndex = 2
let head = array[0..<endIndex] // [3, 4]
let tail = array[startIndex..<array.count] // [6, 7]
let shiftedArray = tail + head // [6, 7, 3, 4]
for element in shiftedArray {
// do something
}
Here's a solution using a custom SequenceType & associated GeneratorType, as suggested by Sulthan in a comment above.
On the plus side, this sequence is really rather nicely readable and flexible. For instance:
let startIndex = 3
let endIndex = 2
let array = [3, 4, 5, 6, 7]
ModuloSequence(start: startIndex, end: endIndex, divisor: array.count).map {
array[$0]
}
On the minus side, it's rather verbose to implement (my take on it is, anyway):
struct ModuloSequenceGenerator : GeneratorType {
let end:Int, divisor:Int
private var dividend:Int?
init(start:Int, end:Int, divisor:Int) {
self.dividend = start
self.end = end
self.divisor = divisor
}
mutating func next() -> Int? {
guard let c = dividend where c != end else {
return nil
}
dividend = (c + 1) % divisor
return dividend
}
}
struct ModuloSequence : SequenceType {
let start:Int, end:Int, divisor:Int
func generate() -> ModuloSequenceGenerator {
return ModuloSequenceGenerator(start: start, end: end, divisor: divisor)
}
}

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

Why is my Swift loop failing with error "Can't form range with end < start"?

I have a for loop that checks if a number is a factor of a number, then checks if that factor is prime, and then it adds it to an array. Depending on the original number, I will get an error saying
fatal error: Can't form range with end < start
This happens almost every time, but for some numbers it works fine. The only numbers I have found to work with it are 9, 15, and 25.
Here is the code:
let num = 16 // or any Int
var primes = [Int]()
for i in 2...(num/2) {
if ((num % i) == 0) {
var isPrimeFactor = true
for l in 2...i-1 {
if ((i%l) == 0) {
isPrimeFactor = false;
}//end if
}//end for
if (isPrimeFactor == true) {
primes.append(i)
}//end if
}//end if
}//end for
Swift 5
If you need a loop with dynamic value-range, I suggest that using stride(to:by:) instead of ..< or ...
Basically ..< or ... will be crashed if start_index > end_index.
This will be crash:
let k = 5
for i in 10...k { print("i=\(i)") }
for i in 10..<k { print("i=\(i)") }
How to fix:
let k = 5
for i in stride(from: 10, through: k, by: 1) { print("i=\(i)") }
for i in stride(from: 10, to: k, by: 1) { print("i=\(i)") }
NOTE:
The code above won't print out anything, but it won't be crash when execution.
Also, if you want to stride from a higher number to a lower number then the by parameter needs to be changed to a negative number.
Reference:
http://michael-brown.net/2016/using-stride-to-convert-c-style-for-loops-to-swift-2.2/
http://swiftdoc.org/v2.1/protocol/Strideable/
In your second loop, i will always start at 2, which means you're looping from 2...1
SWIIFT 4
The best way to go is to use stride as by this documentation page:
Generic Function stride(from:to:by:)
for i in stride(from: 10, through: 5, by: -1) { print(i) }
and stride through if you want to include the lowerBound: Generic Function stride(from:through:by:)
Both ClosedRange and CountableRange throw this error unless start <= end. One problem with using stride(from:to:by) is that it returns a Strideable and not a Range, which doesn't work with the "is in range" operator ~=. To handle these cases, I use an extension which gives me a bounds-safe range, where invalid ranges become an empty range:
extension Int {
func until(_ end: Int) -> CountableRange<Int> {
return self <= end ? self..<end : self..<self
}
func through(_ end: Int) -> CountableRange<Int> {
return self <= end ? self..<(end + 1) : self..<self
}
}
Both return CountableRange so that an invalid through range becomes an empty range. (Side note: the name until is chosen because this "safe" range behaves the same as until ranges in Kotlin/Android).
Usage:
for i in 0.until(3) { /* do something */ }
let printRange = { (range: Range<Int>) -> Void in
for i in range {
print(i, terminator: " ")
}
print()
}
printRange(0.until(3)) // prints "0 1 2"
printRange(0.until(0)) // prints ""
printRange(3.until(0)) // prints ""
printRange(0.through(3)) // prints "0 1 2 3"
printRange(0.through(0)) // prints "0"
printRange(3.through(0)) // prints ""
print(0.until(1) ~= -1) // prints "false"
print(0.until(1) ~= 0) // prints "true"
print(0.until(1) ~= 1) // prints "false"
print(0.until(0) ~= 0) // prints "false"
print(1.until(0) ~= 0) // prints "false"
print(0.through(1) ~= -1) // prints "false"
print(0.through(1) ~= 0) // prints "true"
print(0.through(1) ~= 1) // prints "true"
print(0.through(0) ~= 0) // prints "true"
print(1.through(0) ~= 0) // prints "false"
If you want to use range where upperBound < lowerBound, you can add reversed() to it.
for eg: for number in (0...highestPossibleNumber).reversed()
Using a simple solution you can make for loop reverse using Stride and -
func reverseArray(oldarray: [String]) -> [String] {
var newArray = [String]()
let len = oldarray.count
for i in stride(from: len - 1, through: 0, by: -1)
{ newArray.append(oldarray[i])
print(i)
}
return newArray
}
input : print(reverseArray(oldarray: ["World", "Hello"]))
output : ["Hello", "World"]
The easiest solution is to apply ".reversed()" to your array.
Example: array.reversed()

How to compare ranges in Swift?

I'm not sure if it's a bug in XCode or I didn't understand ranges in Swift. Here is some code to show how range works:
let range = 0..<5
contains(range, 0) // true
contains(range, 5) // false
range.startIndex == 0 // true
range.endIndex == 5 // true
let str = "Hello, playground"
str.rangeOfString("Hello")! // 0..<5
Great! Now let's use it real code:
let str = "Hello, playground"
if let range = str.rangeOfString("Hello") {
if range.startIndex == 0 {
print("str starts with 'Hello'")
}
}
I'm getting following error in line that reads if range.startIndex == 0 {
Cannot invoke '==' with an argument lis of type (String.index,
IntegerLiteralConvertible)'
The ~= operator in Swift
Sometimes, we have to check if a number is between a range, and as usual, we do something like :
Check if number is between 0 and 100 include
if number >=0 && number <= 100 {
// TODO:
}
It works, but we can do better and swiftier. The Swift Standard library have an ~= operator, so we can do instead :
if 0...100 ~= number {
// TODO:
}
rangeOfString actually returns a range of String.Indexs and not Ints; the two aren't comparable (even though the playground shows the range as 0..<5). You can read about the reasons for that in the answers to this question.
If you want your example to work then, instead of comparing range.startIndex with 0, you should compare it with str.startIndex:
let str = "Hello, playground"
if let range = str.rangeOfString("Hello") {
if range.startIndex == str.startIndex {
print("str starts with 'Hello'")
}
}
If you need to compare to the range's startIndex with, say, the second character index in the string, then you can use the advance function to increment str.startIndex by 1 and compare range.startIndex to that:
let str = "Hello, playground"
if let range = str.rangeOfString("e") {
if range.startIndex == advance(str.startIndex, 1) {
print("str's 2nd character is 'e'")
}
}
If you need to know the length of the range, then you can use the distance function:
let str = "Hello, playground"
if let range = str.rangeOfString("play") {
let length = distance(range.startIndex, range.endIndex)
print("found a range \(length) characters long")
}