Type checking timeouts
If your solution fails due to a timeout (and it isn't doing something that's inherently slow, e.g. factorizing), it's probably too complex for the type checker to understand. To troubleshoot, try undoing some optimizations (particularly joining strings with flatMap
) and adding explicit type annotations and/or as
-casts to things you suspect the compiler's hung up on.
[!TIP]
Oftentimes, the compiler will give a useful type checking error after you remove optimizations. In this case, you can usually put those optimizations back after fixing the error.
Substrings
let str = "Hello! World"
str.prefix(6) // "Hello!"
str.suffix(5) // "World"
""+([]+str)[3...5] // "lo!"
Splitting
The split function can take a closure that tells it what characters to split on. Split on spaces using:
i.split{$0==" "}
If the string doesn't contain newlines, this will also work:
i.split{$0<"!"}
Typecasting
String
String(i)
can be
"\(i)"
Array
Array(i)
can be
[]+i
Looping
for i in 0...100{print(i)}
(0...100).map{print($0)}
Depending on how many times you use the loop variable, it might be shorter to use for
-in
instead of map
in certain cases. Try them both!
Conditional printing
Usually the same length, but depending on specific situation one can be shorter than the other
if a>0{print(a)}
a>0 ?print(a):()
Argument labels
By wrapping a function or initializer reference in an immediately-executed closure, you can call it without argument labels:
String(repeating:"h",count:3)
{String.init}()("h",3)
["a","b","c"].joined(separator:" ")
{["a","b","c"].joined}()(" ")
This trick works for most functions/initializers with lengthy argument labels, as long as the function isn't generic and doesn't rely solely on the labels for overload resolution.
Key paths
"hello".map{$0.asciiValue!}
"hello".map(\.asciiValue!)
Type inference
Type placeholders
In cases where the compiler can't infer the full type, it can often infer part of the type:
let f={($0 as[String]).map{$0+"hello"}}
let g={$0.map{$0+"hello"}} // error: cannot infer type of closure parameter '$0' without a type annotation
let h={($0 as[_]).map{$0+"hello"}}
This syntax works for generic parameters; Array
, Dictionary
, and Optional
sugar ([_]
, [_:_]
, _?
); tuple types; and function types.
Inference via literals
let f={($0,$1,$2)as(Int,String,Double)}
let g={($0+0,$1+"",$2+0.0)}
Joining strings
If you don't need a separator or don't care about trailing whitespace, you can use flatMap
instead of map
/joined
:
[1,2,3].map{"\($0)"}.joined()
""+[1,2,3].flatMap{"\($0)"}
{[1,2,3].map{"\($0)"}.joined}()(" ")
[1,2,3].map{"\($0) "}.joined()
""+[1,2,3].flatMap{"\($0) "}
It's very easy to time-out the type checker with this trick, so use it with care.