How to use the binary operator "%" with user input "readLine()"? - swift

I have been asked to write a code using If/Else statements. The code is supposed to ask the user to enter a number and then print "This number is even" if the number is even, and print "This number is odd" if the number is odd. To do this, I am using the binary operator "%" in order to find out whether the number imputed is even or odd. The problem is that I keep getting this error that says: "error: binary operator '%' cannot be applied to operands of type 'String?' and 'Int' if a % 2 == 0". I do not know how to make the user input become an Int value instead of the default String so that the binary operator will work.
I have been suggested to try Type Casting, but nothing I do seems to be working.
print("This code will inform you whether the number you input is odd or even.")
print("Please enter a number of your choice.")
var a = readLine()
if a % 2 == 0 {
print("This number is even.")
}
else {
print("This number is odd.")
}
I expect the user to be able to input a number and the computer to tell the user whether the number is odd or even.

readLine() returns an optional string. To unwrap optional there are couple of options in swift, I guess its three options there. One is force unwrapping, second is optional chaining and third is by guard statement. Here in the option below I have used optional chaining to unwrap optional string returned by redLine(). Try this:
if let typed = readLine() {
if let num = Int(typed) {
if num % 2 == 0 {
print("This number is even.")
}
else {
print("This number is odd.")
}
}
} else {
print("Please enter a valid number")
}

Related

How to solve this question that involves function and optionals?

I'm done with the first part, I need help with second question that involves updating the function to return an Int. I've tried to solve it but what I get is an error
If an app asks for a user's age, it may be because the app requires a user to be over a certain age to use some of the services it provides. Write a function called checkAge that takes one parameter of type String. The function should try to convert this parameter into an Int value and then check if the user is over 18 years old. If he/she is old enough, print "Welcome!", otherwise print "Sorry, but you aren't old enough to use our app." If the String parameter cannot be converted into an Int value, print "Sorry, something went wrong. Can you please re-enter your age?" Call the function and pass in userInputAge below as the single parameter. Then call the function and pass in a string that can be converted to an integer.
Go back and update your function to return the age as an integer. Will your function always return a value? Make sure your return type accurately reflects this. Call the function and print the return value.
func checkage(age: String)->Int?
{
if let age_type = Int(age)
{
if age_type > 18 {
return "Welcome!"
}
else if age_type < 18 {
return"Sorry, but you aren't old enough to use our app."
}
}
else {
return "Sorry, something went wrong. Can you please re-enter your age?"
}
return age_type
}
print(checkage(age:"23"))
error: 3. Exercise - Functions and Optionals.xcplaygroundpage:20:12: error: use of unresolved identifier 'age_type'
return age_type
^~~~~~~~
Several issues:
Inside your method, it looks like you're returning strings, but the method signature (checkage(age: String) -> Int?) indicates you're returning an optional integer value.
Your age_type is a non-optional value, but you're using if let, which is one way to unwrap optionals. No idea what's up there.
Your age_type declaration is less than or greater than, but if it's exactly equal, you'd hit your else block indicating there's something wrong, but that would be exactly age (assuming it would work, which it won't).
Anyway, here's a cleaned up version of what I think you're trying to do.
Based on your declarations in what you originally wrote, I think you may or may not have an age, so if you don't have one, you want to return an error. With that assumption, I made the age parameter optional (?). The guard statement checks if there's an age, if there is one, it unwraps it, otherwise it returns a string saying it ****ed up.
If it gets past the guard, then if it's over 18, it returns the "Welcome" string, otherwise it returns an error.
func check(age: Int?) -> String {
guard let age = age else {
return "Sorry, something went wrong. Can you please re-enter your age?"
}
if age > 18 {
return "Welcome!"
} else {
return "Sorry, but you aren't old enough to use our app."
}
}
Here are the outputs for the various ranges:
// Sorry, something went wrong. Can you please re-enter your age?
print(check(age: nil))
// Welcome!
print(check(age: 19))
// Sorry, but you aren't old enough to use our app.
print(check(age: 18))
Additionally, if you're writing a function to evaluate a number, it should take a number as a parameter. If you're getting the number from a textField, do the conversion from text to string on the view. If you're using a text field to get the number, look up ways to restrict input in the text field to a valid number string (your hint is look up UITextFieldDelegate methods.

Swift reduce - why is value optional?

Why is total optional on line return total + 1?
return first.enumerated().reduce(0) { total, letter in
let index = first.index(first.startIndex, offsetBy: letter.offset)
if first[index] != second[index]{
return total + 1
}
return total
}
Value of optional type 'Int?' must be unwrapped to a value of
type'Int' Coalesce using '??' to provide a default when the optional
value contains 'nil' Force-unwrap using '!' to abort execution if
the optional value contains 'nil'
So this fixes it:
return first.enumerated().reduce(0) { total, letter in
let index = first.index(first.startIndex, offsetBy: letter.offset)
if first[index] != second[index]{
return total! + 1
}
return total
}
If I break it down the change happens on adding let index....
OK - This returns the total count of first and total is not optional:
return first.reduce(0) { total, letter in
return total + 1
}
OK - This enumerated and total is not optional:
return first.enumerated().reduce(0) { total, letter in
return total + 1
}
ERROR - This gets a compile error that total is optional
return first.enumerated().reduce(0) { total, letter in
let index = first.index(first.startIndex, offsetBy: letter.offset)
return total + 1
}
In order for you to get this result at all (as far as I can tell), the enclosing function must return an Int?. The implication is that reduce can return an optional. Absent the conditional, the compiler can determine that reduce will never return nil, i.e., total is never nil. So, the compiler infers that the return type of the closure is Int. The compiler appears to be entangling type inferencing for the reduce closure and total. Once you add the conditional, the compiler is incapable of determining whether the reduce will return nil or not. Now when it unnecessarily infers the type for total it gets it wrong.
To me this looks like a case of Swift type inferencing gone astray. Clearly, total is never nil based on the documentation of enumerated.
If you modify the code slightly you get the expected result:
return first.enumerated().reduce(0) { (total: Int, letter) in
let index = first.index(first.startIndex, offsetBy: letter.offset)
if first[index] != second[index]{
return total + 1
}
return total
}
Swift makes a lot of type inferences and it is really great because I get strong typing while retaining many of the benefits of a dynamic language. In my experience, however, swift's inferences can be mystifying sometimes. It handles arcane situations with ease and stumbles over something I think is obvious.
It looks like a bug to me.

Argument labels do not match any availble overloads

I'm trying to create an anagram tester, and I'm pretty sure the code I have should work, but I'm getting an error 'Argument labels '(_:)' do not match any available overloads' I've looked at the other posts regarding the same error, but I'm still not sure what this means or how to fix it.
var anagram1 : String!
var anagram2 : String!
var failure : Bool = false
var counter : Int = 0
print("Please enter first word: ")
anagram1 = readLine()
print("Please enter Second word: ")
anagram2 = readLine()
if anagram1.count == anagram2.count {
for i in anagram1.characters{
if (!failure){
failure = true
for y in anagram2.characters {
counter += 1
if i == y {
failure = false
anagram2.remove(at: String.Index(counter)) // error here
}
}
}
else {
print("these words are not anagrams")
break;
}
}
if (!failure) {
print("these words ARE anagrams")
}
}
else{
print ("these words aren't even the same length you fucking nonce")
}
To answer your first question: the error message Argument labels '(_:)' do not match any available overloads means that you've given a function parameter names or types that don't match anything Swift knows about.
The compiler is also trying to tell you what parameters to look at. '(_:)' says that you're calling a function with an unlabeled parameter. (That means a value without any parameter name. A common example of a function that would look like this is print("something"). In Swift documentation, this would look like print(_:).
Finally, overloads are ways to call a function with different information. Again using the print function as an example, you can call it multiple ways. A couple of the most common overloads would be:
// print something, followed by a newline character
print("something")
// print something, but stay on the same line
// (end with an empty string instead of the default newline character)
print("something", terminator: "")
Documented, these might look like print(_:) and print(_:, terminator:).
Note: these are broken down for explanation. The actual Swift documentation shows func print(_: Any..., separator: String, terminator: String) which covers a number of different overloads!
Looking at the line where the error occurs, you see a function call and an initializer (which is essentially a function). Documented, the way you've entered the parameters, the functions would look like: remove(at:) and String.Index(_:).
String.Index(_:) matches the parameters of the error message, so that's where your error is. There is no overload of the String.Index initializer that takes an unnamed parameter.
To fix this error, you need to find the correct way to create a String.Index parameter for the remove(at:) function. One way might be to try something like this:
for y in anagram2.characters.enumerated() {
// `y` now represents a `tuple`: (offset: Int, element: Character)
// so, you don't need `counter` anymore; use `offset` instead
if i == y.element { //`i` is a Character, so it can compare to `element`
...
let yIndex: String.Index = anagram2.index(anagram2.startIndex, offsetBy: y.offset)
anagram2.remove(at: yIndex)
...
}
}
However, there are other issues with your code that will cause further errors.
For one, you're looping through a string (anagram2) and trying to change it at the same time - not a good thing to do.
Good luck to you in solving the anagram problem!
Thanks for the help Leo but I found a way of doing it :)
if anagram1.count == anagram2.count {
for i in anagram1.characters{
if (!failure){
counter = -1
failure = true
for y in anagram2.characters {
counter += 1
if i == y {
failure = false
if counter < anagram2.count {
anagram2.remove(at: (anagram2.index(anagram2.startIndex, offsetBy: counter)))
break;
}
}
}
}

Why is a non-optional value printed as optional?

I've read Non-optional shown as optional on print but that doesn't help my question.
I'm returning a Integer, but once it's printing it's being printed as optional. Why?
I'm trying to solve a code challenge. The goal is to:
Write an extension for collections of integers that returns the number
of times a specific digit appears in any of its numbers.
Here is my implementation:
extension Collection where Iterator.Element == Int {
func challenge37(count character : Character) -> Int?{
guard nil != Int(String(character)) else{
print("character wasn't an integer")
return nil
}
var counts : [Int] = []
for item in self{
var counter = 0
let stringInt = String(describing: item)
for currentCharacter in stringInt.characters{
if character == currentCharacter{
counter += 1
}
}
counts.append(counter)
}
guard let min = counts.min() else{
print("no min")
return nil
}
return min
}
}
As you can see here I'm printing it:
print([5,15,512,522].challenge37(count: "5")) // Optional(1)
Inside the function your returning an Int. However the actual signature of your method is Int? meaning it is in fact an optional and you got it wrong!
Basically your method signature is correct. But when you call the function you're getting an optional as the response and must unwrap it.
print([5,15,512,522].challenge37(count: "5")!) // 1
Additionally had you paid close attention you would have noticed that Xcode must gave you a warning (and solutions to solve it)
Expression implicitly coerced from Int? to Any
Xcode gave you the warning because it found out that you're attempting to print an optional and knows that's usually unwanted. Obviously its solution is to unwrap it either through force unwrap or defaulting.

Idiomatic way to unwrap an integer string input

Sorry if this is a basic question, but I am learning Swift and I don’t understand how to unwrap inputs from readLine().
For example, I would expect this
let n: Int = Int(readLine(strippingNewline: true) ?? -1)
to work, but it doesn’t. Nor does replacing the -1 with a "-1" to match types.
let n: Int = Int(readLine(strippingNewline: true) ?? "-1")
What is the “right” way to do this then? Can someone explain exactly what Swift is doing when it unwraps optionals and uses them as arguments for a constructor like Int?
The whole concept of optionals is a bit foreign to me (a Python programmer); in Python you handle invalid input the “ghetto way”, putting out fires only after they happen:
try:
n = int(input())
except ValueError:
n = None
but I assume the paradigm in Swift is different.
There are two optionals at play here.
First, readLine(strippingNewline: true) is optional. It can return nil if there's no input recieved prior to the End of File (EOF) character being received. It must be unwrapped before being passed into Int()
Secondly, Int() is optional, because the String it was given may not be a valid string representation of a number.
Do not use -1 in Swift to represent "no value". This is called a sentinel value, and it's exactly what optionals are invented to prevent. How do you distinguish between a -1 meaning "no/invalid input", and a -1 meaning "the user's input was -1?
Here is how I would write this code:
guard let userInput = readLine(strippingNewline: true) else {
// If we got to here, readLine(strippingNewLine:) returned nil
fatalError("Received EOF before any input was given")
}
// If we got to here, then userInput is not nil
if let n = Int(userInput) {
// If we got to here, then userInput contained a valid
// String representation of an Int
print("The user entered the Int \(n)")
}
else {
// If we got to here, then userInput did not contain a
// valid String representation of an Int.
print("That is not a valid Int.")
}