Introduction
Bob is a lackadaisical teenager.
He likes to think that he’s very cool.
And he definitely doesn’t get excited about things.
That wouldn’t be cool.
When people talk to him, his responses are pretty limited.
Instructions
Instructions
Your task is to determine what Bob will reply to someone when they say something to him or ask him a question.
Bob only ever answers one of five things:
- “Sure.”
This is his response if you ask him a question, such as “How are you?”
The convention used for questions is that it ends with a question mark.
- “Whoa, chill out!”
This is his answer if you YELL AT HIM.
The convention used for yelling is ALL CAPITAL LETTERS.
- “Calm down, I know what I’m doing!”
This is what he says if you yell a question at him.
- “Fine. Be that way!”
This is how he responds to silence.
The convention used for silence is nothing, or various combinations of whitespace characters.
- “Whatever.”
This is what he answers to anything else.
Dig Deeper
if expressions
if expressions
object Bob {
fun hey(input: String): String {
val msg = input.trim()
if (msg.isEmpty()) return "Fine. Be that way!"
val isQuestion = msg.endsWith('?')
val isYelling = ('A'..'Z').any { msg.contains(it) } && msg == msg.uppercase()
if (isYelling)
return if (isQuestion) "Calm down, I know what I'm doing!" else "Whoa, chill out!"
else return if (isQuestion) "Sure." else "Whatever."
}
}
In this approach you have a series of if expressions to evaluate the conditions.
As soon as the right condition is found, the correct response is returned.
An object declaration is used to define Bob as essentially a singleton object instantiation of the class.
This is sufficient, since there is no object state that needs to change with each call of the hey method.
The String trim() method is applied to the input to eliminate any whitespace at either end of the input.
If the string has no characters left, it returns the response for saying nothing.
Note that a `null` `string` would be different from a `String` of all whitespace.
A `null` `String` would throw a `NullPointerException` if `trim()` were applied to it.
A question is determined by use of the endsWith() method to see if the input ends with a question mark.
A range of A..Z is defined to look for uppercase English alphabetic characters.
The first half of the isYelling implementation
if (('A'..'Z').any { msg.contains(it) }
is constructed from the range and the any method
to ensure there is at least one uppercase letter character in the String.
The lambda of any uses the it keyword to refer to the single Char parameter for the lambda,
and passes it to the contains method to check if the character is in the input String.
The check that there is any alphabetic character is needed, because the second half of the condition tests that the uppercased input is the same as the input.
If the input were only "123" it would equal itself uppercased, but without letters it would not be a yell.
If isYelling is true, then a ternary expresson is used to return either the response for a yelled question or just a yell.
If isYelling is false, then a ternary expression is used to return either the response for a question or a plain statement.
Answer List
Answer List
object Bob {
private val answers =
listOf("Whatever.", "Sure.", "Whoa, chill out!", "Calm down, I know what I'm doing!")
fun hey(input: String): String {
val msg = input.trim()
if (msg.isEmpty()) return "Fine. Be that way!"
val isQuestion = if (msg.endsWith('?')) 1 else 0
val isYelling = if (('A'..'Z').any { msg.contains(it) } && msg == msg.uppercase()) 2 else 0
return answers[isQuestion + isYelling]
}
}
In this approach you define a List that contains Bob’s answers, and each condition is given a score.
The correct answer is selected from the List by using the score as the List index.
An object declaration is used to define Bob as essentially a singleton object instantiation of the class.
This is sufficient, since there is no object state that needs to change with each call of the hey method.
The listOf method is used to create a list of Bob’s answers.
The String trim() method is applied to the input to eliminate any whitespace at either end of the input.
If the string has no characters left, it returns the response for saying nothing.
Note that a `null` `string` would be different from a `String` of all whitespace.
A `null` `String` would throw a `NullPointerException` if `trim()` were applied to it.
A question is determined by use of the endsWith() method to see if the input ends with a question mark.
A range of A..Z is defined to look for uppercase English alphabetic characters.
The first half of the isYelling implementation
if (('A'..'Z').any { msg.contains(it) }
is constructed from the range and the any method
to ensure there is at least one uppercase letter character in the String.
The lambda of any uses the it keyword to refer to the single Char parameter for the lambda,
and passes it to the contains method to check if the character is in the input String.
The check that there is any alphabetic character is needed, because the second half of the condition tests that the uppercased input is the same as the input.
If the input were only "123" it would equal itself uppercased, but without letters it would not be a yell.
The conditions of being a question and being a yell are assigned scores through the use of the ternary expression.
For example, giving a question a score of 1 would use an index of 1 to get the element from the answers List, which is "Sure.".
| isYelling | isQuestion | Index | Answer |
|---|
false | false | 0 + 0 = 0 | "Whatever." |
false | true | 0 + 1 = 1 | "Sure." |
true | false | 2 + 0 = 2 | "Whoa, chill out!" |
true | true | 2 + 1 = 3 | "Calm down, I know what I'm doing!" |
when expression
when expressions
object Bob {
fun hey(statement: String): String =
when {
statement.isQuestion() && statement.isYelling() -> "Calm down, I know what I'm doing!"
statement.isQuestion() -> "Sure."
statement.isYelling() -> "Whoa, chill out!"
statement.isSilence() -> "Fine. Be that way!"
else -> "Whatever."
}
private fun String.isSilence(): Boolean = this.isBlank()
private fun String.isQuestion(): Boolean = this.trim().endsWith('?')
private fun String.isYelling(): Boolean = any(Char::isLetter) && toUpperCase() == this
}
In this approach you have a when expression containing different so-called branches that can be matched using the corresponding patterns.
As soon as one of these patterns on the left side of the arrow (->) is matched …
- the value on the right side
- the block on the right side is executed and the value retuned from the block
… is returned from the when expression.
Only one branch is matched in one execution of the when expression. The branches are matched from top to bottom and the first branch in which the condition evaluates to true is selected.
If none of the given conditions matches the else branch is selected and returned.
Depending on what patterns are on the left side of your branches the order of branches is important to the correct execution of the `when` expression since the first matching branch is selected.
An object declaration is used to define Bob as essentially a singleton object instantiation of the class.
This is sufficient, since there is no object state that needs to change with each call of the hey method.
Inside this object there are some private extension methods as members of the object. This adds these methods to the String data type for private usage of these methods in this object. This allows calling the methods directly on the String instead of passing the String to the method.
(More about extension methods in general here)
These extension methods check for:
isSilence(): a blank string
isQuestion(): a string with the last non-whitespace-character being a question mark
isYelling(): a string with all letters in uppercase
When combining these methods as in the when expression above you can map all the cases required by the exercise.
Source: Exercism kotlin/bob