Why is this handmade square root function in Swift not returning the value, but throws the error? - ios

Just trying to create an analog of sqrt() in Swift, but it throws .noRoot in all the matched cases.
Also I add the error .outOfBound, this is working correctly.
import UIKit
enum WrongNumber: Error {
case outOfBounds
case noRoot
}
func mySqrt(_ number: Int) throws -> Int {
if number < 1 || number > 10_000 {
throw WrongNumber.outOfBounds
}
var result = 0
for i in 1...10_000 {
if i * i == number {
result = i
} else {
throw WrongNumber.noRoot
}
}
return result
}
var number = 1000
do {
let result = try mySqrt(number)
print(result)
}
catch WrongNumber.outOfBounds {
print("You're puting a wrong number. Please try again with range from 1 to 10_000")
}
catch WrongNumber.noRoot {
print("There is no square root in your number")
}

You should return once you find it
func mySqrt(_ number: Int) throws -> Int {
if number < 1 || number > 10_000 {
throw WrongNumber.outOfBounds
}
for i in 1...10_000 {
if i * i == number {
return i
}
}
throw WrongNumber.noRoot
}

Related

Generate consecutive and same number on Array effectively in Swift

I have an example of a case in the application to create a numeric pin pattern that should not have a consecutive number and the same number of all.
Examples of PIN patterns that are rejected are as follows:
123456,
234567,
345678,
654321,
765432,
876543,
000000 and other similar PIN patterns.
var rejectedPinList: [[Int]] = [[Int]]()
var consecutiveNumber = [0,1,2,3,4,5,6,7,8,9,0]
func incrementNumber(currentIndex: Int) -> [Int] {
var rejectedPinPattern: [Int] = [Int]()
for currentIndex in stride(from: currentIndex, to: currentIndex+6, by: 1){
rejectedPinPattern.append(consecutiveNumber[currentIndex])
}
return rejectedPinPattern
}
func decrementNumber(currentIndex: Int) -> [Int] {
var rejectedPinPattern: [Int] = [Int]()
for currentIndex in stride(from: currentIndex, to: currentIndex-6, by: -1){
rejectedPinPattern.append(consecutiveNumber[currentIndex])
}
return rejectedPinPattern
}
func constantNumber(currentIndex: Int) -> [Int] {
var rejectedPinPattern: [Int] = [Int]()
for _ in currentIndex...currentIndex+6 {
rejectedPinPattern.append(consecutiveNumber[currentIndex])
}
return rejectedPinPattern
}
for number in consecutiveNumber {
rejectedPinList.append(constantNumber(currentIndex: number))
if number < 5 {
rejectedPinList.append(incrementNumber(currentIndex: number))
} else if number > 5 {
rejectedPinList.append(decrementNumber(currentIndex: number))
} else {
rejectedPinList.append(incrementNumber(currentIndex: number))
rejectedPinList.append(decrementNumber(currentIndex: number))
}
}
func inputPin(pin: [Int]) {
if rejectedPinList.contains(pin) {
print("Pin Rejected!")
} else {
}
}
inputPin(pin: [8,7,6,5,4,3]) // Should be Rejected!
What I'm looking for is to be more effective than the algorithm code I made above in generating consecutive & same numbers. Because in my opinion, the code I made is too long and not very effective and may be wasteful. Thank you!
Instead of computing a list of all invalid pins in advance, you can verify the given pin by computing the set of all differences of adjacent digits. A pin is invalid if the set consists of -1, 0, or +1 only:
func validatePIN(_ pin: [Int]) -> Bool {
if pin.isEmpty { return false }
let diffs = Set(zip(pin, pin.dropFirst()).map(-))
return diffs.count != 1 || abs(diffs.first!) > 1
}
As the question was to improve efficiency, the approach below this implements the some initial checks before it starts looping through the array to minimise the total number of iterations/time.
func validatePin(_ pin: [Int], minLength: Int = 2 ) -> Bool {
guard pin.count >= max(minLength, 2) else {return false}
guard Set(pin).count != 1 else {return false} //all the same
guard abs(pin.first! - pin.last!) == pin.count - 1 else {return true} //can't be a sequence
let delta = pin.first! < pin.last! ? -1 : 1
for index in (0...pin.count - 2) {
if pin[index] - pin[index + 1] != delta {return true} //items not sequential
}
return false //items are sequential
}
I think this should do what you want. It checks to see if there are any consecutive digits that have an absolute difference that isn't 1. If so then the PIN may be valid (pending a check for repeated digits).
To check for repeated digits, the digits are added to an NSCountedSet. If the count for any digit is the same as the number of digits then the PIN is invalid.
func validatePIN(_ candidate: [Int]) -> Bool {
guard !candidate.isEmpty else {
return false
}
let digitSet = NSCountedSet()
var possiblyValid = false
var lastSign: Int?
for i in 0..<candidate.count {
digitSet.add(candidate[i])
if i > 0 && !possiblyValid {
let difference = candidate[i]-candidate[i-1]
let thisSign = difference.signum()
if abs(difference) != 1 {
possiblyValid = true
} else if let sign = lastSign, sign != thisSign {
possiblyValid = true
}
lastSign = thisSign
}
}
for digit in digitSet {
if digitSet.count(for: digit) == candidate.count {
return false
}
}
return possiblyValid
}
print(validatePIN([]))
print(validatePIN([8,7,6,5,3,3]))
print(validatePIN([8,7,6,5,4,3]))
print(validatePIN([2,2,2,2,2,2]))
print(validatePIN([1,2,3,4,3,2]))
gives:
false
true
false
false
true
You could also add a test for minimum length in the guard statement
Thank you all for helping me. I also improvise my algorithm. Here's my code:
func validatePIN(_ pin: [Int]) -> Bool {
if (pin.isEmpty == true) ||
(pin[0] < 5 && pin == Array(pin[0]...pin[0]+5)) ||
(pin[0] > 5 && pin == Array(stride(from: pin[0], through: pin[0]-5, by: -1)) ||
(pin.allSatisfy({ $0 == pin[0] }))) { return false }; return true
}

Swift Little endian hex value to decimal

I'm having difficulties implementing a function converting hex value(little endian) to decimal value.
So I'm writing function:
func convertHexLittleEndianToDeciaml(input:String) -> (int)
and Input is always 4 bytes(so 8 characters in input string)
value for convertHexLittleEndianToDeciaml("606d0000") should return 28,000
You can write something like this:
(See UPDATEs)
func convertHexLittleEndianToDeciaml(input:String) -> Int32 {
if let beValue = Int32(input, radix: 16) where input.characters.count == 8 {
return beValue.byteSwapped
} else {
//or `fatalError()` or `return 0` or ...
return Int32.min
}
}
print(convertHexLittleEndianToDeciaml("606d0000")) //->28000
UPDATE
Sorry, but the code above have some overflow issue, happens with something like "FF010000":
func convertHexLittleEndianToDeciaml(input:String) -> Int32 {
if let beValue = UInt32(input, radix: 16) where input.characters.count == 8 {
return Int32(bitPattern: beValue.byteSwapped)
} else {
//or `fatalError()` or `return 0` or ...
return Int32.min
}
}
UPDATE2
So, I have found that returning a valid Int32 in error case might cause a bug which cannot easily be found. I recommend you to change the return type to Optional and return nil in error case.
func convertHexLittleEndianToDeciaml(input:String) -> Int32? {
guard let beValue = UInt32(input, radix: 16) where input.characters.count == 8 else {
return nil
}
return Int32(bitPattern: beValue.byteSwapped)
}
if let value = convertHexLittleEndianToDeciaml("606d0000") {
print(value) //->28000
} else {
print("Hex format invalid")
}
Here's a solution that works for longer numbers that I wrote:
func convert(number: String) -> Int {
var formatted = number
if number.count <= 16 {
let difference = 16 - number.count
for _ in 0..<difference {
formatted.append("0")
}
} else {
return 0
}
let value = UInt64(formatted, radix: 16) ?? 0
let z = value.byteSwapped
let final = UInt64(bitPattern: Int64(z))
return Int(final)
}

How to make a "for" loop on the condition of a number interval Xcode Swift2

Hey I'm trying to figure out how to tally up soccer goals on the condition that the goal was scored in under 45 minutes, but the func has some slight errors with swift 2. Any help? Thanks!
Code:
var barcelonavsRealMadrid1goals : [String : Int] = ["barcelonaGoal1":21,"RealMadridGoal2":23,"barcelonaGoal3":24,"RealMadridGoal4":27]
func Run() {
var goalCount=0
for (goal,numbers) in barcelonavsRealMadrid1goals{
for(var number in numbers) {
if(number < 45)
goalCount++
}
}
You have an extra for..in loop in there that's not needed:
for(var number in numbers) {
It also has an extraneous ( and ) around it
for var number in numbers {
Here is a working version of your code:
var barcelonavsRealMadrid1goals = ["barcelonaGoal1":21,"RealMadridGoal2":23,"barcelonaGoal3":24,"RealMadridGoal4":27]
func run() -> Int { // functions should start with lower case
var goalCount=0
for (_,numbers) in barcelonavsRealMadrid1goals where numbers < 45 {
goalCount++
}
return goalCount
}
let goalCount = run()
And the functional way would be something like:
let goalCount = goals.reduce(0) {
if $0.1.1 < 45 {
return $0.0 + 1
}
return $0.0
}
With explanation:
var goals = [
"barcelonaGoal1" :21,
"RealMadridGoal2":23,
"barcelonaGoal3" :24,
"RealMadridGoal4":27,
"RealMadridGoal5":45]
// For our use reduce takes an initial value of Int
// and a combine function of type
// (Int, (String, Int)) -> Int
//
// Reduce will call the closure once with
// each value in the map and the previous return value
let goalCount = goals.reduce(0, combine: {
(initial:Int, current:(key:String, value:Int)) -> Int in
var currentCount = initial
// print to show input and output of closure
print( "parameters:(\(initial), (\"\(current.key)\", \(current.value)))", terminator:", ")
defer {
print("return:\(currentCount)")
}
// end printing
if current.value < 45 {
++currentCount // add 1 to the running total
return currentCount
}
return currentCount
})
// console output:
// parameters:(0, ("barcelonaGoal1", 21)), return:1
// parameters:(1, ("RealMadridGoal4", 27)), return:2
// parameters:(2, ("RealMadridGoal5", 45)), return:2
// parameters:(2, ("RealMadridGoal2", 23)), return:3
// parameters:(3, ("barcelonaGoal3", 24)), return:4
For solving of you're problem try to use functional programing that is introduced in swift :
var barcelonavsRealMadrid1goals : [String : Int] = ["barcelonaGoal1":95,"RealMadridGoal2":23,"barcelonaGoal3":24,"RealMadridGoal4":27]
var filtered = barcelonavsRealMadrid1goals.filter { (team:String, minute:Int) -> Bool in
var state = false
if (minute > 45)
{
return true
}
return state
}
let totalCount = filtered.count
Try this method.
func Run() {
var goalCount=0
for (_, score) in barcelonavsRealMadrid1goals {
if(score < 45) {
goalCount++
}
}
print(goalCount)
}

Stuck in a loop. Very strange because the code sometimes work and sometimes just freezes

I am writing a puzzle game for an IOS. In my code I need to fill an array with some random (and non-random numbers) that will represent the main data structure.
func Random(r : Range<Int>) -> Int {
return Int(arc4random_uniform(UInt32(r.endIndex - r.startIndex))) + r.startIndex
} // function to generate random number
var arrWithColors = [Int]() // array that will hold the numbers
//function to that check if an array contains a number in a range already
func checkForNumberInArrayWithRange(r: Range <Int>, n: Int ) -> Bool {
for i in r.startIndex..<r.endIndex {
if arrWithColors[i] == n { return true }
}
return false
}
// here is the main function where i keep getting stuck. Out of let's say five times it would only work 3 or even less.
func randHexWithTag() {
var rNumber : Int = Random(0...5)
for i in 0...5 {
while (true) {
rNumber = Random(0...5)
if !checkForNumberInArrayWithRange(0...5, n: rNumber) {
break
}
}
arrWithColors[i] = rNumber
}
arrWithColors[10] = arrWithColors[1]
for i in 6...11 {
while(true) {
rNumber = Random(0...5)
if ((rNumber == arrWithColors[0] && i == 9) || (rNumber == arrWithColors[2] && i == 11)) {
continue
}
if !checkForNumberInArrayWithRange(6...11, n: rNumber) {
break
}
}
if (i != 10) {
arrWithColors[i] = rNumber
}
}
arrWithColors[13] = arrWithColors[4]
for i in 12...17 {
while(true) {
rNumber = Random(0...5)
if (rNumber == arrWithColors[3] && i == 12) || (rNumber == arrWithColors[5] && i == 14) {
continue
}
if !checkForNumberInArrayWithRange(12...17, n: rNumber) {
break
}
}
if (i != 13) {
arrWithColors[i] = rNumber
}
}
}
The above code will ALWAYS fail during the first call to checkForNumberInArrayWithRange on this line:
if arrWithColors[i] == n { return true }
That is because arrWithColors is empty, and index i is out of range

How to convert AnyBase to Base10?

I found some code to encode a Base10-String with to a custom BaseString:
func stringToCustomBase(encode: Int, alphabet: String) -> String {
var base = alphabet.count, int = encode, result = ""
repeat {
let index = alphabet.index(alphabet.startIndex, offsetBy: (int % base))
result = [alphabet[index]] + result
int /= base
} while (int > 0)
return result
}
... calling it with this lines:
let encoded = stringToCustomBase(encode: 9291, alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
print(encoded)
The encoding above works pretty good. But what about decoding the encoded string?
So because I got no idea how to decode a (in this case Base62 [alphabet.count=62]) to a human readable string (in this case [Base10]) any help would be super appreciated.
PS: (A full code solution is not required, I can also come up with some kind of pseudo-code or maybe just a few-lines of code)
This is what I've tried so far:
func reVal(num: Int) -> Character {
if (num >= 0 && num <= 9) {
return Character("\(num)")
}
return Character("\(num - 10)A");
}
func convertBack() {
var index = 0;
let encoded = "w2RDn3"
var decoded = [Character]()
var inputNum = encoded.count
repeat {
index+=1
decoded[index] = reVal(num: inputNum % 62)
//encoded[index] = reVal(inputNum % 62);
inputNum /= 62;
} while (inputNum > 0)
print(decoded);
}
Based on the original algorithm you need to iterate through each character of the encoded string, find the location of that character within the alphabet, and calculate the new result.
Here are both methods and some test code:
func stringToCustomBase(encode: Int, alphabet: String) -> String {
var base = alphabet.count, string = encode, result = ""
repeat {
let index = alphabet.index(alphabet.startIndex, offsetBy: (string % base))
result = [alphabet[index]] + result
string /= base
} while (string > 0)
return result
}
func customBaseToInt(encoded: String, alphabet: String) -> Int? {
let base = alphabet.count
var result = 0
for ch in encoded {
if let index = alphabet.index(of: ch) {
let mult = result.multipliedReportingOverflow(by: base)
if (mult.overflow) {
return nil
} else {
let add = mult.partialValue.addingReportingOverflow(alphabet.distance(from: alphabet.startIndex, to: index))
if (add.overflow) {
return nil
} else {
result = add.partialValue
}
}
} else {
return nil
}
}
return result
}
let startNum = 234567
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let codedNum = stringToCustomBase(encode: startNum, alphabet: alphabet)
let origNun = customBaseToInt(encoded: codedNum, alphabet: alphabet)
I made the customBaseToInt method return an optional result in case there are characters in the encoded value that are not in the provided alphabet.
You can achieve this via reduce:
enum RadixDecodingError: Error {
case invalidCharacter
case overflowed
}
func customRadixToInt(str: String, alphabet: String) throws -> Int {
return try str.reduce(into: 0) {
guard let digitIndex = alphabet.index(of: $1) else {
throw RadixDecodingError.invalidCharacter
}
let multiplied = $0.multipliedReportingOverflow(by: alphabet.count)
guard !multiplied.overflow else {
throw RadixDecodingError.overflowed
}
let added = multiplied.partialValue.addingReportingOverflow(alphabet.distance(from: alphabet.startIndex, to: digitIndex))
guard !added.overflow else {
throw RadixDecodingError.overflowed
}
$0 = added.partialValue
}
}
I used the exception throwing mechanism so that the caller can distinguish between invalid characters or overflow errors.

Resources