I was using this extension method to generate a random number:
func Rand(_ range: Range<UInt32>) -> Int {
return Int(range.lowerBound + arc4random_uniform(range.upperBound - range.lowerBound + 1))
}
I liked it b/c it was no nonsense, you just called it like this:
let test = Rand(1...5) //generates a random number between 1 and 5
I honestly don't know why things need to be so complicated in Swift but I digress..
So i'm receiving an error now in Swift3
No '...' candidates produce the expected contextual result type 'Range<UInt32>'
Would anyone know what this means or how I could get my awesome Rand function working again? I guess x...y no longer creates Ranges or x..y must be explicitly defined as UInt32? Any advice for me to make things a tad easier?
Thanks so much, appreciate your time!
In Swift 3 there are four Range structures:
"x" ..< "y" ⇒ Range<T>
"x" ... "y" ⇒ ClosedRange<T>
1 ..< 5 ⇒ CountableRange<T>
1 ... 5 ⇒ CountableClosedRange<T>
(The operators ..< and ... are overloaded so that if the elements are stridable (random-access iterators e.g. numbers and pointers), a Countable Range will be returned. But these operators can still return plain Ranges to satisfy the type checker.)
Since Range and ClosedRange are different structures, you cannot implicitly convert a them with each other, and thus the error.
If you want Rand to accept a ClosedRange as well as Range, you must overload it:
// accepts Rand(0 ..< 5)
func Rand(_ range: Range<UInt32>) -> Int {
return Int(range.lowerBound + arc4random_uniform(range.upperBound - range.lowerBound))
}
// accepts Rand(1 ... 5)
func Rand(_ range: ClosedRange<UInt32>) -> Int {
return Int(range.lowerBound + arc4random_uniform(range.upperBound + 1 - range.lowerBound))
}
A nice solution is presented in Generic Range Algorithms
(based on How to be DRY on ranges and closed ranges? in the swift-users mailing list).
It uses the fact that both CountableRange and CountableClosedRange
are collections, and in fact a RandomAccessCollection.
So you can define a single (generic) function which accepts both open and closed
integer ranges:
func rand<C: RandomAccessCollection>(_ coll: C) -> C.Iterator.Element {
precondition(coll.count > 0, "Cannot select random element from empty collection")
let offset = arc4random_uniform(numericCast(coll.count))
let idx = coll.index(coll.startIndex, offsetBy: numericCast(offset))
return coll[idx]
}
rand(1...5) // random number between 1 and 5
rand(2..<10) // random number between 2 and 9
but also:
rand(["a", "b", "c", "d"]) // random element from the array
Alternatively as a protocol extension method:
extension RandomAccessCollection {
func rand() -> Iterator.Element {
precondition(count > 0, "Cannot select random element from empty collection")
let offset = arc4random_uniform(numericCast(count))
let idx = index(startIndex, offsetBy: numericCast(offset))
return self[idx]
}
}
(1...5).rand()
(2..<10).rand()
["a", "b", "c", "d"].rand()
You could rewrite Rand() to use Int if that is your primary use case:
func Rand(_ range: Range<Int>) -> Int {
let distance = UInt32(range.upperBound - range.lowerBound)
return range.lowerBound + Int(arc4random_uniform(distance + 1))
}
Or as kennytm points out, use Rand(1..<6)
Related
I implemented a function to calculate the hamming distance using Swift, it uses the xor operation x ^ y to get the different bits. Then, I convert the result from an Int to a String of 8 characters which is the 8 bit representation of my Xor. However, I am getting the error:
Compile Error: ambiguous use of 'filter'
class Solution {
func hammingDistance(_ x: Int, _ y: Int) -> Int {
let xor = x ^ y //xor: compares bits
let xorBinary = String(xor, radix: 2)
let xor8BitBinaryStr = String(repeating: Character("0"), count: 8 - xorBinary.count) + xorBinary
return xor8BitBinaryStr.filter({ $0 == "1" }).count
}
}
let c = Solution()
print(c.hammingDistance(1, 4)) //prints 2
You can filter like this to avoid confusion for the compiler,
let items = xor8BitBinaryStr.filter({ $0 == "1"})
return items.count
OR
return Array(xor8BitBinaryStr).filter({ $0 == "1" }).count
To solve this, declare the type of the xor8BitBinaryStr before you perform operations on it.
let xor8BitBinaryStr : `data type here` = String(repeating: Character("0"), count: 8 - xorBinary.count) + xorBinary
In Swift 4.0, there are two filter methods on String which only differ by their return type.
One returns String, the other [Character].
If you don't explicitly declare the type of the return you expect, it defaults to String.
Therefore, if you want to get [Character], you need to do something like this:
let chars: [Character] = xor8BitBinaryStr.filter({ $0 == "1" })
return chars.count
EDIT: This was a bug in Swift that was fixed, presumably in 4.1. It was marked Resolved on 11/17/17. See https://bugs.swift.org/browse/SR-5175?jql=text%20~%20%22filter%22
How can return an Int from a range of numbers in Swift?
I want to return an Int from a range of two numbers. Ultimately my goal is to assign the returned Int value to an indexPath.row of a tableview in cellforpathatindex method. I have written the extension but when I print the return value which is in the example below is k, I am only getting the min value instead of the entire range of values.
extension Range {
func returnIndexValue(min: Int, max: Int) -> Int {
var indexArray = [Int]()
let range = (min..<max)
for i in range {
return i
}
for p in indexArray {
return p
}
return max
}
}
let range: Range<Int> = 1..<10
var k = range.returnIndexValue(min: 6, max: 100)
print(k)
if you want to return all the range of int values in an array then you can do it like that :
func returnIndexValue(min: Int, max: Int) -> [Int] {
return Array(min...max)
}
And you don't need to use an extension for that.
Your function terminates at the first return it hits which is when it returns min in the first loop.
Edit
Your comments show you still don't get the problem with your code. A return statement exits the function. If you have a return in a loop as you do, the loop and the function are exited, the first time you execute the return. There's no way to magically go back and continue executing the loop. You're done.
Do you want a sequence of all the numbers in the range? Because a Range of Int is already a sequence. So you can create an array of all the values in the range simply by doing this:
let arrayOfInts = Array(1 ..< 4) // [ 1, 2, 3 ]
Your for ... in statement already does what you need, just replace the return with whatever it is you want to do for each value. For example:
for i in range
{
print(i)
}
prints all the numbers from min to max - 1
When we write the following:
for i in 1...10 {
//do stuff
}
I want know what type have the range 1...10 to use it in function call for example:
myFunc(1...10)
If you put a breakpoint after defining let range = 1..<10, you will see that it's actually not a Range structure, but rater a CountableRange (or CountableClosedRange for 0...10)
Docs: CountableRange, CountableClosedRange
Functions:
func printRange(range: CountableRange<Int>) {
for i in range { print ("\(i)") }
}
func printRange(range: CountableClosedRange<Int>) {
for i in range { print ("\(i)") }
}
Usage:
let range = 1..<10
printRange(range: range)
let closedRange = 1...10
printRange(range: closedRange)
Generic function:
Since both structs conform to RandomAccessCollection protocol, you can implement only one function like this:
func printRange<R>(range: R) where R: RandomAccessCollection {
for i in range { print ("\(i)") }
}
This article about ranges in Swift 3 may also be useful.
for i in 1...10 {
print(i)
}
Output :
1
2
3
4
5
6
7
8
9
10
your this loop is run 10 time if you start it with 0 then your loop run 11 time . hope you clear with start with 0 and 1 what is different
and ya as you ask that myfunc(1...10) that means
Range(1..<11)
- startIndex : 1
- endIndex : 11
These are called Ranges (see here - https://developer.apple.com/reference/swift/range)
So myfunc would be declared as
func myfunc(range: Range)
I am making fuction that calculate factorial in swift. like this
func factorial(factorialNumber: UInt64) -> UInt64 {
if factorialNumber == 0 {
return 1
} else {
return factorialNumber * factorial(factorialNumber - 1)
}
}
let x = factorial(20)
this fuction can calculate untill 20.
I think factorial(21) value bigger than UINT64_MAX.
then How to calculate the 21! (21 factorial) in swift?
func factorial(_ n: Int) -> Double {
return (1...n).map(Double.init).reduce(1.0, *)
}
(1...n): We create an array of all the numbers that are involved in the operation (i.e: [1, 2, 3, ...]).
map(Double.init): We change from Int to Double because we can represent bigger numbers with Doubles than with Ints (https://en.wikipedia.org/wiki/Double-precision_floating-point_format). So, we now have the array of all the numbers that are involved in the operation as Doubles (i.e: [1.0, 2.0, 3.0, ...]).
reduce(1.0, *): We start multiplying 1.0 with the first element in the array (1.0*1.0 = 1.0), then the result of that with the next one (1.0*2.0 = 2.0), then the result of that with the next one (2.0*3.0 = 6.0), and so on.
Step 2 is to avoid the overflow issue.
Step 3 is to save us from explicitly defining a variable for keeping track of the partial results.
Unsigned 64 bit integer has a maximum value of 18,446,744,073,709,551,615. While 21! = 51,090,942,171,709,440,000. For this kind of case, you need a Big Integer type. I found a question about Big Integer in Swift. There's a library for Big Integer in that link.
BigInteger equivalent in Swift?
Did you think about using a double perhaps? Or NSDecimalNumber?
Also calling the same function recursively is really bad performance wise.
How about using a loop:
let value = number.intValue - 1
var product = NSDecimalNumber(value: number.intValue)
for i in (1...value).reversed() {
product = product.multiplying(by: NSDecimalNumber(value: i))
}
Here's a function that accepts any type that conforms to the Numeric protocol, which are all builtin number types.
func factorial<N: Numeric>(_ x: N) -> N {
x == 0 ? 1 : x * factorial(x - 1)
}
First we need to declare temp variable of type double so it can hold size of number.
Then we create a function that takes a parameter of type double.
Then we check, if the number equal 0 we can return or do nothing. We have an if condition so we can break the recursion of the function. Finally we return temp, which holds the factorial of given number.
var temp:Double = 1.0
func factorial(x:Double) -> Double{
if(x==0){
//do nothing
}else{
factorial(x: x-1)
temp *= x
}
return temp
}
factorial(x: 21.0)
I make function calculate factorial like this:
func factorialNumber( namber : Int ) -> Int {
var x = 1
for i in 1...namber {
x *= i
}
return x
}
print ( factorialNumber (namber : 5 ))
If you are willing to give up precision you can use a Double to roughly calculate factorials up to 170:
func factorial(_ n: Int) -> Double {
if n == 0 {
return 1
}
var a: Double = 1
for i in 1...n {
a *= Double(i)
}
return a
}
If not, use a big integer library.
func factoruial(_ num:Int) -> Int{
if num == 0 || num == 1{
return 1
}else{
return(num*factoruial(num - 1))
}
}
Using recursion to solve this problem:
func factorial(_ n: UInt) -> UInt {
return n < 2 ? 1 : n*factorial(n - 1)
}
func factorial(a: Int) -> Int {
return a == 1 ? a : a * factorial(a: a - 1)
}
print(factorial(a : 5))
print(factorial(a: 9))
Swift 2.2 deprecated the C-style loop. However in some cases, the new range operator just doesn't work the same.
for var i = 0; i < -1; ++i { ... }
and
for i in 0..<-1 { ... }
The later one will fail at run-time. I can wrap the loop with an if, but it's a bit cluttered. Sometimes this kind of loop is useful.
Any thoughts?
Use cases
You need to enumerate all elements of an array, except the last one.
You need to enumerate all whole integer numbers in a decimal range, but the range can be like [0.5, 0.9] and so there's no integers (after some maths), which results in an empty loop.
Although it's not as "pretty", you can use stride:
for var i in 0.stride(to: -1, by: -1) {
print(i)
}
Mimicking the "C-style loop"
Not entirely pretty, but you can wrap the range:s upper bound with a max(0, ..) to ascertain it never takes negative values.
let foo : [Int] = []
for i in 0..<max(0,foo.count-1) {
print(i)
}
I'd prefer, however, the from.stride(to:by) solution (that has already been mentioned in the other answers, see e.g. Michael:s answer).
I think it's valuable to explicitly point out, however, that from.stride(to:by) neatly returns an empty StrideTo (or, if converted to an array: an empty array) if attempting to stride to a number that is less than from but by a positive stride. E.g., striding from 0 to -42 by 1 will not attempt to stride all the way through "∞ -> -∞ -> -42" (i.e., an error case), but simply returns an empty StrideTo (as it should):
Array(0.stride(to: -42, by: 1)) // []
// -> equivalent to your C loop:
for i in 0.stride(to: foo.count-1, by: 1) {
print(i)
}
Use case 1: enumerate all but the last element of an array
For this specific use case, a simple solution is using dropLast() (as described by Sulthan in the comments to your question) followed by forEach.
let foo = Array(1...5)
foo.dropLast().forEach { print($0) } // 1 2 3 4
Or, if you need more control over what to drop out, apply a filter to your array
let foo = Array(1...5)
foo.filter { $0 < foo.count }.forEach { print($0) } // 1 2 3 4
Use case 2: enumerate all integers in a decimal range, allowing this enumeration to be empty
For your decimal/double closed interval example ([0.6, 0.9]; an interval rather than a range in the context of Swift syntax), you can convert the closed interval to an integer range (using ceil function) and apply a forEach over the latter
let foo : (ClosedInterval<Double>) -> () = {
(Int(ceil($0.start))..<Int(ceil($0.end)))
.forEach { print($0) }
}
foo(0.5...1.9) // 1
foo(0.5...0.9) // nothing
Or, if you specifically want to enumerate the (possible) integers contained in this interval; use as en extension fit to your purpose:
protocol MyDoubleBounds {
func ceilToInt() -> Int
}
extension Double: MyDoubleBounds {
func ceilToInt() -> Int {
return Int(ceil(self)) // no integer bounds check in this simple example
}
}
extension ClosedInterval where Bound: MyDoubleBounds {
func enumerateIntegers() -> EnumerateSequence<(Range<Int>)> {
return (self.start.ceilToInt()
..< self.end.ceilToInt())
.enumerate()
}
}
Example usage:
for (i, intVal) in (1.3...3.2).enumerateIntegers() {
print(i, intVal)
} /* 0 2
1 3 */
for (i, intVal) in (0.6...0.9).enumerateIntegers() {
print(i, intVal)
} /* nothing */
For reference:
In swift 3.0 stride is now defined globally which makes for loop look more natural:
for i in stride(from: 10, to: 0, by: -1){
print(i)
} /* 10 9 8 7 6 5 4 3 2 1 */
For Swift 3 and need to change the "index"
for var index in stride(from: 0, to: 10, by: 1){}