Struggling to understand the code - which tries to return the decimal digit 'n' places in from the right of the number - swift

I'm new to Swift and is trying to learn the concept of extension. I saw this code in "the swift programming language", which tries to return the decimal digit 'n' places in from the right of the number. The code work fine, but I am struggling to understand how the code actually works.
Could someone explain it to me?
extension Int {
subscript(var digitIndex: Int) -> Int {
var decimalBase = 1
while digitIndex > 0 {
decimalBase *= 10
--digitIndex
}
return (self / decimalBase) % 10
}
}
746381295[0]
// returns 5
746381295[1]
// returns 9
746381295[2]
// returns 2
746381295[8]
// returns 7
746381295[9]

Extensions work by adding capability to existing types, with the caveat that they cannot introduce their own storage. In the case in point:
/*1*/ extension Int {
/*2*/ subscript(var digitIndex: Int) -> Int {
/*3*/ var decimalBase = 1
/*4*/ while digitIndex > 0 {
/*5*/ decimalBase *= 10
/*6*/ --digitIndex
/*7*/ }
/*8*/ return (self / decimalBase) % 10
}
}
Line 1 defines the extension as applying to all Int types.
Line 2 is setting up a new subscript operator for an Int, which will allow you to have 12345[4] and produce 'something'. Lines 3-8 define that something.
The while in lines 4-8 is multiplying decimalBase by 10 for 'digitIndex' times. A bit of a weird way of doing it, but never mind. The upshot is if digitIndex is 1, decimalBase is 10; if it's 2, decimal base is 100; 3 it's 1000; etc.
The guts is in line 8. First it retrieves self. Since the extension applies to an Int, self will be that integer value. It then divides it by decimalBase, and because they're both integers, any fractional part will be lost. Therefore in the case of 746381295[2] decimalBase will be 100 so you get 7463812. Then it uses '%' to get the remainder of the division by 10. So 7463812 divided by 10 is 746381 with a remainder of 2. So the returned value is 2.
Hope that explains it.
Pre-empting your question, I might use for in this case, instead of the while:
for _ in 0..<digitIndex {
decimalBase *= 10
}
I haven't thought too much about how often the above loops, it might run once to often or once too few, but you get the idea.
Even better would be to use the 'raising to the power' operator (not really sure what it's called).
decimalBase = 10 ^^ digitIndex
Then the whole definition could boil down to:
return (self / (10 ^^ digitIndex)) % 10
I will leave it to you to decide whether that's better or not.
Either way, I wouldn't really create this extension, and I assume it was just done for the purpose of demonstration.

Simply put, decimalBase is calculated to be 1 with an index of 0, 10 with an index of 1, 100 with an index of 2, 1,000 with an index of 3, and so on. In other words, decimalBase ends up equal to 10 ^ digitIndex.
So look at the case where digitIndex is 3, for instance. decimalBase will end up being 1,000, so:
746381259 / 1000 == 746381
and then:
746381 % 10 == 1
so that's how you get from 746381259[3] to 1.

Related

Array Performing XOR On Itself With Offset

Trying to implement an autocorrelation algorithm, meaning, for example:
let exampleData: [Float] = [1, 2, 3, 4, 5]
Trying to find the fastest way to evaluate 1 ^ 2 + 2 ^ 3 + 3 ^ 4 + 4 ^ 5.
Essentially, iterate through the array, and for every element, calculate the result of XOR between it and another element a set distance away.
Trouble is, this also has to be done for many different values of the offset.
Right now I just have a nested for loop, and I don't know how to make it faster...
var data: [Bool]
var result: [Int]
...
for offset in start..<end {
for index in 0..<(end - offset) {
if (data[index] ^ data[index + frequency]) {
result[offset] += 1
}
}
}
Sounds like you might want windows(ofCount:) from swift-algorithms:
https://github.com/apple/swift-algorithms/blob/main/Guides/Windows.md
That will give you a sliding window through any collection, and if your offset is relatively small (or you actually want the whole window, e.g. to do a moving average), that will be great.
The swift-algorithms stuff is nice since it's more optimized than whatever you'll do ad hoc, plus offers lazy eval.
You might also consider aligning and zipping up your sequence and then mapping over that, e.g.:
zip(data, data.dropFirst(offset))
.map { $0 ^ $1 }
...and so on

Better way to find sums in a grid in Swift

I have an app with a 6x7 grid that lets the user input values. After each value is obtained the app checks to find if any of the consecutive values create a sum of ten and executes further code (which I have working well for the 4 test cases I've written). So far I've been writing if statements similar to the below:
func findTens() {
if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue + rowOneColumnFourPlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue + rowOneColumnFourPlaceHolderValue + rowOneColumnFivePlaceHolderValue) == 10 {
//code to execute
}
That's not quite halfway through row one, and it will end up being a very large set of if statements (231 if I'm calculating correctly, since a single 7 column row would be 1,2-1,2,3-...-2,3-2,3,4-...-67 so 21 possibilities per row). I think there must be a more concise way of doing it but I've struggled to find something better.
I've thought about using an array of each of the rowXColumnYPlaceHolderValue variables similar to the below:
let rowOnePlaceHolderArray = [rowOneColumnOnePlaceHolderValue, rowOneColumnTwoPlaceHolderValue, rowOneColumnThreePlaceHolderValue, rowOneColumnFourPlaceHolderValue, rowOneColumnFivePlaceHolderValue, rowOneColumnSixPlaceHolderValue, rowOneColumnSevenPlaceHolderValue]
for row in rowOnePlaceHolderArray {
//compare each element of the array here, 126 comparisons
}
But I'm struggling to find a next step to that approach, in addition to the fact that those array elements then apparently because copies and not references to the original array anymore...
I've been lucky enough to find some fairly clever solutions to some of the other issues I've come across for the app, but this one has given me trouble for about a week now so I wanted to ask for help to see what ideas I might be missing. It's possible that there will not be another approach that is significantly better than the 231 if statement approach, which will be ok. Thank you in advance!
Here's an idea (off the top of my head; I have not bothered to optimize). I'll assume that your goal is:
Given an array of Int, find the first consecutive elements that sum to a given Int total.
Your use of "10" as a target total is just a special case of that.
So I'll look for consecutive elements that sum to a given total, and if I find them, I'll return their range within the original array. If I don't find any, I'll return nil.
Here we go:
extension Array where Element == Int {
func rangeOfSum(_ sum: Int) -> Range<Int>? {
newstart:
for start in 0..<count-1 {
let slice = dropFirst(start)
for n in 2...slice.count {
let total = slice.prefix(n).reduce(0,+)
if total == sum {
return start..<(start+n)
}
if total > sum {
continue newstart
}
if n == slice.count && total < sum {
return nil
}
}
}
return nil
}
}
Examples:
[1, 8, 6, 2, 8, 4].rangeOfSum(10) // 3..<5, i.e. 2,8
[1, 8, 1, 2, 8, 4].rangeOfSum(10) // 0..<3, i.e. 1,8,1
[1, 8, 3, 2, 9, 4].rangeOfSum(10) // nil
Okay, so now that we've got that, extracting each possible row or column from the grid (or whatever the purpose of the game is) is left as an exercise for the reader. 🙂

How to properly call another function within a function in swift?

I'm learning an swift and I've written two functions and have tried them on their own they both work well. However when I try to call one function within another one I can't seem to get the desired out-put that I seek.
The task at hand is that one function should print Prime numbers whilst the other is to calculate and check if the number is prime. I am supposed to call the check if number is prime from the print Prime numbers function.
below is my code:
This function calculates whether or not the X:Int is a prime number. It's set to a boolean because I'm supposed to print "true" or "false" in the function below it.
func isPrime(_ x: Int) -> Bool {
if(x%2 == 0 || x%3 == 0){
if(x == 2 || x == 3){
return(true)
}
return(false)
}
else{
//if the number is less than or equal to 1, we'll say it's not prime
if(x <= 1){
return(false)
}
}
return true
}
This piece calculates the printing of the prime number from 1 to n.
func PrintPrimes(upTo n: Int) {
for x in 1...n {
var count = 0
for num in 1..<x {
isPrime(x)
count += 1
}
if count <= 1 {
print(isPrime(x))
}
}
}
This piece only runs twice and i'm not exactly sure why. I don't know if its because i'm not calling it correctly or I'd have to change up some calculations.
All help is appreciated
EDIT:
Here is the original printPrimes() before I decided to call isPrime within the function. This function calculates the prime numbers only and prints them up to n.
func printPrimes(upTo n: Int) {
for x in 1...n {
var count = 0
for num in 1..<x {
if x % num == 0 {
count += 1
}
}
if count <= 1 {
print(x)
}
}
}
Your second routine is printing only two values because it is calling isPrime, but never doing anything conditional on the value returned, but rather incrementing count regardless. And since you’re printing only if count is <= 1, that will happen only for the first two values of n.
But let’s say you were trying to print the prime numbers up to a certain number, you could do:
func printPrimes(upTo n: Int) {
for x in 1...n {
if isPrime(x) {
print(x)
}
}
}
(As a matter of convention, in Swift, when we say “through n”, we’d iterate 1...n, and if someone said “up to n”, we’d iterate 1..<n. But because your original code snippet uses upTo in conjunction with 1...n, I’ll use that here, but just note that this isn’t very consistent with standard Swift API patterns.)
Unfortunately, isPrime is not correct, either. So you’ll have to fix that first. For example, consider 25. That is not divisible by 2 or 3, but isn’t prime, either.
If you look at the original printPrimes that was provided, what it effectively does is say “by how many whole integers less than x is x divisible ... if only divisible by one other number (namely 1), then it’s a prime.” That logic, although not efficient, is correct. You should go ahead and use that inside your isPrime routine. But that “is divisible by 2 or 3” logic is not correct.
You can do it this way, in your printPrimes you can loop up to the number you want and just check if the number is prime by calling the function with the number. But you have to check your isPrime function. Your printPrimes should only do what its name says (print the prime numbers up to n) and all the logic to check if the number is prime should be on your isPrime function.
Also its a good practice to use camelCase on functions, you should rename your function to printPrimes instead of PrintPrimes.
func printPrimes(upTo n: Int) {
for x in 1...n {
if isPrime(x) {
print(x)
}
}
}

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

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

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.