How do I generate a random number not including one without using a while loop? - swift

Let's say I want to generate a random number between 1 and 100, but I don't want to include 42. How would I do this without repeating the random method until it is not 42.

Updated for Swift 5.1
Excluding 1 value
var nums = [Int](1...100)
nums.remove(at: 42)
let random = Int(arc4random_uniform(UInt32(nums.count)))
print(nums[random])
Excluding multiple values
This extension of Range does provide a solution when you want to exclude more than 1 value.
extension ClosedRange where Element: Hashable {
func random(without excluded:[Element]) -> Element {
let valid = Set(self).subtracting(Set(excluded))
let random = Int(arc4random_uniform(UInt32(valid.count)))
return Array(valid)[random]
}
}
Example
(1...100).random(without: [40,50,60])
I believe the computation complexity of this second solution is O(n) where n is the number of elements included in the range.
The assumption here is the no more than n excluded values are provided by the caller.

appzYourLife has some great general purpose solutions, but I want to tackle the specific problem in a lightweight way.
Both of these approaches work roughly the same way: Narrow the range to the random number generator to remove the impossible answer (99 answers instead of 100), then map the result so it isn't the illegal value.
Neither approach increases the probability of an outcome relative to another outcome. That is, assuming your random number function is perfectly random the result will still be random (and no 2x chance of 43 relative to 5, for instance).
Approach 1: Addition.
Get a random number from 1 to 99. If it's greater than or equal to the number you want to avoid, add one to it.
func approach1()->Int {
var number = Int(arc4random_uniform(99)+1)
if number >= 42 {
number = number + 1
}
return number
}
As an example, trying to generate a random number from 1-5 that's not 3, take a random number from 1 to 4 and add one if it's greater than or equal to 3.
rand(1..4) produces 1, +0, = 1
rand(1..4) produces 2, +0, = 2
rand(1..4) produces 3, +1, = 4
rand(1..4) produces 4, +1, = 5
Approach 2: Avoidance.
Another simple way would be to get a number from 1 to 99. If it's exactly equal to the number you're trying to avoid, make it 100 instead.
func approach2()->Int {
var number = Int(arc4random_uniform(99)+1)
if number == 42 {
number = 100
}
return number
}
Using this algorithm and narrowing the range to 1-5 (while avoiding 3) again, we get these possible outcomes:
rand(1..4) produces 1; allowed, so Result = 1
rand(1..4) produces 2, allowed, so Result = 2
rand(1..4) produces 3; not allowed, so Result = 5
rand(1..4) produces 4, allowed, so Result = 4

Related

Why do we have to write -1 after .count in this Swift code?

In the following Swift code:
self.numbers[2] = Int.random(in: 0...self.symbols.count-1)
Why do we have to write -1?
I don't understand the code.
When you are using A...B, that range includes B in it. See ...(_:_:) docs. So if you say -
Int.random(in: 0...self.symbols.count-1)
It means range starts at 0 and ends at symbols.count-1 including both.
Say an array has 2 elements, it's count is 2, but valid indices are 0, 1 (2 is not a valid index), so you are just making sure that it is restricted to valid index values.
Other way to write the same would be - A..<B, in this range, B is not included. See ..<(_:_:) docs. Following is same as above.
Int.random(in: 0..<self.symbols.count)
You are using ClosedRange here. It is a range which includes both start and end value of the range. You can also used simple Range, which is open so to say. It only includes start value and not the final value.
Lets take an example.
let a = 1 ... 10 // includes all values from 1 to 10
let b = 1 ..< 10 // includes values from 1 to 9
So, basically what you are writing here,
self.numbers[2] = Int.random(in: 0 ... self.symbols.count - 1)
is equivalent to open range using,
self.numbers[2] = Int.random(in: 0 ..< self.symbols.count)
such that you dont need to add -1 to it.
Int.random can take both ClosedRange and Range, here and here.
Here are your code:
self.numbers[2] = Int.random(in: 0...self.symbols.count-1)
It says: your third item in numbers array will be assigned by the random item of symbols array
But how to get the random item of symbols array? You'll get it by its index.
The indexes of an array starting from 0, so, for the last element of array, its index will be the array length - 1, for example, with [1,2,3], the last element's index will be 2.
Here, you used Closed Range, it will include the last element, so if you don't minus count by one, the last index will be 3 (because array.count will return the length of the array), which is produce out of index error

How to compare random numbers in Swift

I’m a beginner in programming and playing around with the arc4random_uniform() function in Swift. The program I’m making so far generates a random number from 1-10 regenerated by a UIButton. However, I want the variable ’highest' that gets initialised to the random number to update if the next generated number is larger than the one currently held in it. For example the random number is 6 which is stored in highest and if the next number is 8 highest becomes 8. I don't know how to go about this. I have connected the UIButton to an IBAction function and have the following code:
var randomValue = arc4random_uniform(11) + 1
highest = Int(randomValue)
if (Int(randomValue) < highest) {
// Don’t know what to do
}
Initialise highest to 0
Every time you generate a new random number, replace the value of highest with the higher of the two numbers
highest = max(highest, randomValue)
The max() function is part of the Swift standard library and returns the larger of the two passed in vales.
edited to add
Here's a playground showing this with a bit more detail, including casting of types:
var highest: Int = 0
func random() -> Int {
let r = arc4random_uniform(10) + 1
return Int(r)
}
var randomValue = random()
highest = max(highest, randomValue)
You can see that multiple calls persist the highest value.

Why does passing an unnamed function as transform to array add one to iteration count in playground in furthest abstractions

I'm in the process of getting comfortable passing unnamed functions as arguments and I am using this to practice with, based off of the examples in the Swift Programming Guide.
So we have an array of Ints:
var numbers: Int[] = [1, 2, 3, 4, 5, 6, 7]
And I apply a transform like so: (7)
func transformNumber(number: Int) -> Int {
let result = number * 3
return result
}
numbers = numbers.map(transformNumber)
Which is equal to: (7)
numbers = numbers.map({(number: Int) -> Int in
let result = number * 3
return result;
})
Which is equal to: (8)
numbers = numbers.map({number in number * 3})
Which is equal to: (8)
numbers = numbers.map({$0 * 3})
Which is equal to: (8)
numbers = numbers.map() {$0 * 3}
As you can see in the following graphic, the iteration count in the playground sidebar shows that in the furthest abstraction of a function declaration, it has an 8 count.
Question
Why is it showing as 8 iterations for the last two examples?
It's not showing 8 iterations, really. It's showing that 8 things executed on that line. There were 7 executions as part of the map function, and an 8th to do the assignment back into the numbers variable.
It looks like this could probably provide more helpful diagnostics. I would highly encourage you to provide feedback via https://bugreport.apple.com.
Slightly rewriting your experiment to use only closures, the call counts still differ by one:
Case 1: Explicitly specifying argument types (visit count is 7)
var f1 = {(number: Int) -> Int in
let result = number * 3
return result
}
numbers.map(f1)
Case 2: Implicit argument types (visit count is 8)
var f2 = {$0 * 3}
numbers.map(f2)
If the (x times) count reported by the REPL does indeed represent a count of visits to that code location, and noting that the count is greater by one in cases where the closure type arguments are not explicitly specified (e.g. f2), my guess is that at least in the playground REPL, the extra visit is to establish actual parameter types and fill that gap in the underlying AST.

How to take one particular number or a range of particular number from a set of number?

I am looking for to take one particular number or range of numbers from a set of number?
Example
A = [-10,-2,-3,-8, 0 ,1, 2, 3, 4 ,5,7, 8, 9, 10, -100];
How can I just take number 5 from the set of above number and
How can I take a range of number for example from -3 to 4 from A.
Please help.
Thanks
I don't know what you are trying to accomplish by this. But you could check each entry of the set and test it it's in the specified range of numbers. The test for a single number could be accomplished by testing each number explicitly or as a special case of range check where the lower and the upper bound are the same number.
looping and testing, no matter what the programming language is, although most programming languages have builtin methods for accomplishing this type of task (so you may want to specify what language are you supposed to use for your homework):
procfun get_element:
index=0
for element in set:
if element is 5 then return (element,index)
increment index
your "5" is in element and at set[index]
getting a range:
procfun getrange:
subset = []
index = 0
for element in set:
if element is -3:
push element in subset
while index < length(set)-1:
push set[index] in subset
if set[index] is 4:
return subset
increment index
#if we met "-3" but we didn't met "4" then there's no such range
return None
#keep searching for a "-3"
increment index
return None
if ran against A, subset would be [-3,-8, 0 ,1, 2, 3, 4]; this is a "first matched, first grabbed" poorman's algorithm. on sorted sets the algorithms can get smarter and faster.

binary to decimal in objective-c

I want to convert the decimal number 27 into binary such a way that , first the digit 2 is converted and its binary value is placed in an array and then the digit 7 is converted and its binary number is placed in that array. what should I do?
thanks in advance
That's called binary-coded decimal. It's easiest to work right-to-left. Take the value modulo 10 (% operator in C/C++/ObjC) and put it in the array. Then integer-divide the value by 10 (/ operator in C/C++/ObjC). Continue until your value is zero. Then reverse the array if you need most-significant digit first.
If I understand your question correctly, you want to go from 27 to an array that looks like {0010, 0111}.
If you understand how base systems work (specifically the decimal system), this should be simple.
First, you find the remainder of your number when divided by 10. Your number 27 in this case would result with 7.
Then you integer divide your number by 10 and store it back in that variable. Your number 27 would result in 2.
How many times do you do this?
You do this until you have no more digits.
How many digits can you have?
Well, if you think about the number 100, it has 3 digits because the number needs to remember that one 10^2 exists in the number. On the other hand, 99 does not.
The answer to the previous question is 1 + floor of Log base 10 of the input number.
Log of 100 is 2, plus 1 is 3, which equals number of digits.
Log of 99 is a little less than 2, but flooring it is 1, plus 1 is 2.
In java it is like this:
int input = 27;
int number = 0;
int numDigits = Math.floor(Log(10, input)) + 1;
int[] digitArray = new int [numDigits];
for (int i = 0; i < numDigits; i++) {
number = input % 10;
digitArray[numDigits - i - 1] = number;
input = input / 10;
}
return digitArray;
Java doesn't have a Log function that is portable for any base (it has it for base e), but it is trivial to make a function for it.
double Log( double base, double value ) {
return Math.log(value)/Math.log(base);
}
Good luck.