Naming this function is a bit difficult because this is a (contrived) programming task. My suggestion would be something like
func randomInt(in optionalInts: [Int?]?) -> Int
for the following reasons:
- Swift “getter” functions usually do not have a “get” prefix in their name.
in
is used as an argument label in similar functions, like the random(in:)
method.
- Abbreviations like
oArr
should be avoided.
For a real application one could surely find a better name from the context.
“The body of the function has to be a single-line of code” is actually a bad requirement. It is meaningless, since one can always put arbitrary code in a single line of Swift. What is perhaps meant is that the body has to be a single expression. That is possible (as you demonstrated), but it decreases the legibility of the program.
I'll ignore that requirement for a moment and come back to it at the end.
Optional chaining with
optionalInts?.randomElement()
is a good start. That expression evaluates to a “double optional” of type Optional<Optional<Int>>
or Int??
for short. The following cases are possible:
- If
optionalInts
is nil
then the above expression evaluates to .none
.
- If
optionalInts
is not nil
but randomElement()
selects nil
from the array then the expression evaluates to .some(.none)
. The same happens if the array is empty.
- Otherwise the expression evaluates to
.some(.some(x))
where x
is an element of the array.
In the last case the function should return x
, on all other cases it should return some random integer in the range 0...100.
The Optional Pattern can be used to test if a value can be unwrapped twice, either with a switch
statement
func randomInt(in optionalInts: [Int?]?) -> Int {
switch optionalInts?.randomElement() {
case let element??:
element
default:
Int.random(in: 1...100)
}
}
or with a if case let
expression:
func randomInt(in optionalInts: [Int?]?) -> Int {
if case let element?? = optionalInts?.randomElement() {
element
} else {
Int.random(in: 1...100)
}
}
Note that we need Int.random
only once, and not twice as in your solution.
If you add a function description then this becomes fairly readable.
It is possible to achieve the same goal with a single expression and two nil-coalescing operators, each of which decreases the optionality by one:
func randomInt(in optionalInts: [Int?]?) -> Int {
return (optionalInts?.randomElement() ?? nil) ?? Int.random(in: 1...100)
}
This is almost what you did, but still avoids the repetition of Int.random
. Here the expression
(optionalInts?.randomElement() ?? nil)
evaluates to a “simple optional” Int?
, which is .none
in the cases 1 and 2 above, and .some(x)
in case 3.
Int.random(in: 1...100))
feels clunky. ConsideroArr?.randomElement().flatMap { $0 } ?? Int.random(in: 1...100)
. Adjust the naming of the function and the argument label to make the code better readable. \$\endgroup\$