finding a number in a range swift 3 - swift

I have a number that I get from JSON, this number represents an age. Users give me a range of two ages and may code is supposed to check if this number I'm getting from JSON is in the range.
here is my code and it gives me error
Type of Expression is ambiguous without more context?
let age = "40"
if Int(AgeFrom) ... Int(AgeTO) ~= Int(age) {
print("yes")
}
Update
if let value: AnyObject = response.result.value as AnyObject? {
var ages = String
let json = JSON(value)
for (key, subJson) in json {
ages.append(subJson["age"].string!)
}
guard let min = Int(self.DropDownFrom.selectedItem!) else { return }
guard let max = Int(self.DropDownTo.selectedItem!) else { return }
for fitage in ages {
switch ages
{
case (min...max):
print ("Age is in range")
default:
print ("Nope, not this time")
}
}
Still gives me an error.

You need to unwrap the optionals because the Int(:String) method might not have a valid answer.
Best way to do this is kind of thing is with guard
guard let min = Int(AgeFrom) else { return }
guard let max = Int(AgeTo) else { return }
And from there you can go with the simple if statement:
if (min <= age && age <= max)
{
print ("Age is in range")
}
or get really fancy and use the switch statement pattern matching syntax (which I much prefer)
switch age
{
case (min...max):
print ("Age is in range")
default:
print ("Nope, not this time")
}

if - simplicity and readability
It is a basic thing in programming, checking if an optional is between two other optional values with an if:
if Int(AgeFrom)! <= Int(age)! && Int(AgeTO)! >= Int(age)! {
print("It is in the range!")
}
switch - multiple cases handling
However, I recommend using a switch for case handling:
switch(Int(AgeFrom)! <= Int(age)!, Int(AgeTO)! >= Int(age)!){
case (true,true): print("Yes, it fits the range")
case (false,true): print("Too young!")
case (true,false): print("Too old!")
}
The second solution is far better for multiple cases of the age value, especially when it's outside the range.
Hope it helps!

You can also use optional binding:
if let ageFrom = Int(ageFrom),
let ageTo = Int(ageTo),
ageFrom...ageTo ~= age
{
print("yes")
} else {
print("no")
}

You have to unwrap the optionals:
if Int(AgeFrom)!...Int(AgeTO)! ~= Int(age)! {
print("yes")
}
of course that is the unsafe way of unwrapping, since it will crash if the conversion of AgeFrom, AgeTO or age fail.

Related

How can I compare two different types of data (String and Int) using readLine() on Swift?

everyone! I'm a new member of Stack Overflow, just like I'm beginner on swift programming. I'm making this post to find out a solution for the following case:
I'm creating on Swift an app using the Command Line Tool for inputing data. The app basically works as an authenticator. As an example, if someone types USA for the country name and the age is 17, so the program will return a message like "You can not apply to this position". Otherwise, if the country name is USA and the age is equal or higher than 18, so the message returns is "You can forward to the next step". I've tried many times to set this conditions, but it's not working. I'm already knows that the function readLine() is an Optional String, but how can I make my program work correctly? It follows my code above to you understanding my thoughts.
I really appreciate any help. Again, I'm beginner and I'm already studying Swift languages, but I'm seeking some solution that handles Integers and Strings and comparing both data types. Thank you very much!
My code is:
import Foundation
print("Enter your country: ")
var country = readLine()
print("Enter your age: ")
var age = readLine()
if var country, var age = readLine(){
if country == "USA" && age < "18" {
print("You're not allowed to apply to this position.")
} else {
print("You can forward to the next step.")
}
}
PS: As you see, I'm using wrongly the variable age as an String, but I want to convert it to an Int type and then, check if the country name is the same than the value I assigned to or the age is equal or higher than 18. But not found a solution so far.
I'm trying to find a solution that compares two different types on Swift, using Command Line Tool and the readLine() function to check if a condition is true or not. If it's true, an output message will show that the user can proceed to the next step, otherwise he will not be permitted to follow. I'm keeping for an explanation on internet since few days, but not found anything that might help me. I hope to get some help using the Stack Overflow forum to some useful answer.
First one, readline() means you read the current to the end of current line . As your code when you check condition you call readLine() again. The wrong part is here.
I recommend you to read first then do all your logic. You just need to read only one time at first
print("Enter your country: ")
var country = readLine()
print("Enter your age: ")
var ageString = readLine()
Next, check if it is nil or not ( because option value which is value can be nil)
if country == nil || ageString == nil {
print("Error because one of them is nil")
fatalError()
}
Then check if can convert to Int or not. Reach here you sure that the ageString is not nil because you have checked above. So you just simply convert
guard let ageString = ageString else {
print("Error age nil")
fatalError()
}
guard let age = Int(ageString) else {
print("Error age not a number")
fatalError()
}
Then after all, you just check your condition
Full code will be like this
print("Enter your country: ")
var country = readLine()
print("Enter your age: ")
var ageString = readLine()
// check nil first if nil return or do something first and not get to the rest
if country == nil || ageString == nil {
print("Error because one of them is nil")
fatalError()
}
guard let ageString = ageString else {
print("Error age nil")
fatalError()
}
guard let age = Int(ageString) else {
print("Error age not a number")
fatalError()
}
if country == "USA" && age < 18 {
print("You're not allowed to apply to this position.")
} else {
print("You can forward to the next step.")
}
Other methods is use if let to achieve so no force unwrap
print("Enter your country: ")
var country = readLine()
print("Enter your age: ")
var ageString = readLine()
// check nil first if nil return or do something first and not get to the rest
if country == nil || ageString == nil {
print("Error because one of them is nil")
fatalError()
}
if let ageString = ageString {
if let age = Int(ageString) {
if country == "USA" && age < 18 {
print("You're not allowed to apply to this position.")
} else {
print("You can forward to the next step.")
}
} else {
print("Error age not a number")
fatalError()
}
}
SOLUTION SOLVED!
Hey, guys, first of all I want to thank you all for your helpful answers, which helped me a lot. I've got finally a solution, and am going to share it with you.
What did I done? I just created two variables, one String and another Integer. Then, using the if var to force unwrapping of the Int variable, I've made an if statement to check if the both conditions are true (in the case, if the person is from USA and has an age equals or higher than 18). Now, the program is running on the same way I just wanted. If you are from USA but has no 18 years, output returns a message that you can not apply. Otherwise, you're able to forward.
I'll let the code above. If you want to make some comments or any suggestions, it'll be welcome.
Again, thank you very much for all your answers.
var countryCheck = "USA"
var ageCheck: Int = 18
print("Enter your country: ")
var country = readLine()
print("Enter your age: ")
var age = readLine()
if var countryCheck = country, var ageCheck = Int(age!) {
if countryCheck == "USA" && ageCheck >= 18 {
print("You can apply.")
} else {
print("You can not apply to this position.")
}
}
I hope this help you :)
import Foundation
print("Enter your country: ")
if let country = readLine() {
if let num = Int(country) {
print(num)
}
}
let country = readLine()
let age = readLine()
if let USA = country,
let num1 = Int(USA),
let num2 = Int(USA) {
print("The age of \(num1) and \(num2) is \(num1 + num2)")
}

Guard Case Assignment

Well...here is the code
func howMany() -> Int {
return 10
}
func Call() -> Void {
guard case let output = howMany(), output > 5 else { return }
}
Call()
I do not really understand how the guard case works. This looks pretty much like a pattern matching condition where we compare whether the result of howMany() is equal to output, if it is, assign the value to output and then compare it to the literal value 5. However, when I deleted the line of output > 5, the compiler said, "the guard condition is always true, body is unreachable."
According to the pattern, if we translate it into a switch statement, it looks pretty much like this
switch howMany() {
case let output where output > 5:
break;
}
The question is if it could be directly translated into the switch statement, then there should not be a warning of "the guard condition is always true, body is unreachable" when we delete the where condition.
I hope somebody could shed some light on this.
Consider:
func foo() {
guard case let output = howMany(), output > 5 else {
print("less than or equal to 5")
return
}
print("\(output) is greater than 5")
}
That is roughly equivalent to:
func bar() {
switch howMany() {
case let output where output > 5:
print("\(output) is greater than 5")
default:
print("less than or equal to 5")
return
}
}
If you remove that > 5 criteria:
func foo() {
guard case let output = howMany() else {
print("less than or equal to 5")
return
}
print("\(output) is greater than 5")
}
You get your warning:
'guard' condition is always true, body is unreachable
That warning is correct, because the body is unreachable.
And if you do the equivalent in the switch example:
func bar() {
switch howMany() {
case let output:
print("\(output) is greater than 5")
default:
print("less than or equal to 5")
return
}
}
If you do that, you will receive an analogous warning:
default will never be executed
And, again, it makes sense, because default will not be reached.
Now, consider your example switch with no default clause:
func bar() {
switch howMany() {
case let output:
print("output:", output)
}
}
You don't receive a warning here only because there is no default clause (the analog of the "body" of the guard statement).

Matching multiple enums with a single guard case?

I want to match against multiple enums and have something like this:
guard case .north = $0, case .south = $0 else { return }
Is there a way to condense this to a single statement like this?
guard case (. north, . south) = $0 else { return }
The above does not compile, but was hoping I can do something like this. Is there an alternative?
You can put the desired cases into a literal array and use contains to test for a match:
guard [.north, .south].contains($0) else { return }

Using guard with a non-optional value assignment

This is not a question about optional arrays, as one can see in the answers.
I like using guard because it makes your intensions clear. I've used it both for the optional version like this...
guard let c = MyOptionalArray else { return }
as well as for more traditional bounds checking on non-optionals...
guard MyArray.count > 0 else { return }
But now I'd like to use that count in following code. So I did...
guard let c = MyArray.count > 0 else { return }
which doesn't work, obviously, so I did what should...
guard let c = parts.count where c > 1 else { return }
But that says Initializer for conditional binding must have Optional type, not 'Int'. Now I understand the error, and tried a bunch of seemingly obvious changes to the format, but no go. Is there no way to use guard as an assignment on a non-optional value? This seems like something it should be able to do.
If you throw a case in there, it'll work. So as follows:
guard case let c = parts.count where c > 1 else { return }
You can initialize an optional wrapping the non-optional:
guard let count = Optional([42].count), count > 0 else {
return
}
guard let count = .some([42].count), count > 0 else {
return
}
or cast it to an optional:
guard let count = [42].count as Int?, count > 0 else {
return
}
As mentioned in other answers, guard case let also works:
guard case let count = [42].count, count > 0 else {
return
}
guard case let count = [42].count where count > 0 else {
return
}

Unwrapping optional inside of closure using reduce

I have a quick question that is confusing me a little bit. I made a simple average function that takes an array of optional Ints. I check to make sure the array does not contain a nil value but when I use reduce I have to force unwrap one of the two elements in the closure. Why is it that I only force unwrap the second one (in my case $1!)
func average2(array: [Int?]) -> Double? {
let N = Double(array.count)
guard N > 0 && !array.contains({$0 == nil}) else {
return nil
}
let sum = Double(array.reduce(0) {$0+$1!})
let average = sum / N
return average
}
I know it is simple but I would like to understand it properly.
The first parameter of reduce is the sum, which is 0 in the beginning. The second one is the current element of your array which is an optional Int and therefore has to be unwrapped.
Your invocation of reduce does this:
var sum = 0 // Your starting value (an Int)
for elem in array {
sum = sum + elem! // This is the $0 + $1!
}
EDIT: I couldn't get a more functional approach than this to work:
func average(array: [Int?]) -> Double? {
guard !array.isEmpty else { return nil }
let nonNilArray = array.flatMap{ $0 }
guard nonNilArray.count == array.count else { return nil }
return Double(nonNilArray.reduce(0, combine: +)) / Double(nonNilArray.count)
}
You can also discard the second guard if you want something like average([1, 2, nil]) to return 1.5 instead of nil