-
-
Save oderwat/3a6c3aa3ab3cd03a1433d1ed66465a95 to your computer and use it in GitHub Desktop.
Phone Words II for Swift 3.0.1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Cocoa | |
// Missing isWord | |
func isWord(string: String) -> Bool { | |
if let _ = Int(string) { return false } | |
let range = NSSpellChecker.shared().checkSpelling(of: string, startingAt: 0) | |
return range.location == NSNotFound | |
} | |
/*: | |
## Phone Words | |
Generate a collection of words that can be represented by a given phone number. If a phone number contains the digits `1` or `0` then split up the phone number and find the words for each of the substrings as long as each substring has more than one digit. Non-keypad characters can be ignored. Optionally, filter out words so that only dictionary words are present in the result. | |
╔═════╦═════╦═════╗ | |
║ 1 ║ 2 ║ 3 ║ | |
║ ║ abc ║ def ║ | |
╠═════╬═════╬═════╣ | |
║ 4 ║ 5 ║ 6 ║ | |
║ ghi ║ jkl ║ mno ║ | |
╠═════╬═════╬═════╣ | |
║ 7 ║ 8 ║ 9 ║ | |
║ pqrs║ tuv ║wxyz ║ | |
╠═════╬═════╬═════╣ | |
║ * ║ 0 ║ # ║ | |
║ ║ ║ ║ | |
╚═════╩═════╩═════╝ | |
Example | |
`1-8000-356-9377` should return "FLOWERS" | |
*/ | |
/*: | |
Some helper code | |
*/ | |
extension Int { | |
init?(c: Character) { | |
guard let i = Int(String(c)) else { return nil } | |
self = i | |
} | |
} | |
func not<T>(pred : @escaping (T) -> Bool) -> (_ e: T) -> Bool { | |
return { | |
e in | |
return !pred(e) | |
} | |
} | |
func isDigit(c: Character) -> Bool { | |
return ("0"..."9").contains(c) | |
} | |
/*: | |
Used for mapping over a collection, replace items in the collection with values keyed by those items. | |
Example: | |
let r = ["a": 1, "b": 12, "c": 144] | |
["a", "b", "c"].flatMap(transform(r)) | |
Using the pipe-forward operator: | |
["a", "b", "c"].flatMap(r |> transform) | |
*/ | |
func transform<T: Hashable, V>(dict: [T:V]) -> (_ element: T) -> V? { | |
return { | |
element in | |
return dict[element] | |
} | |
} | |
/*: | |
Pipe-forward operator | |
`f(x)` can be written as `x |> f` | |
*/ | |
//infix operator |> { precedence 50 associativity left } | |
infix operator |> : DefaultPrecedence | |
public func |> <T,U>(lhs: T, rhs: (T) -> U) -> U { | |
return rhs(lhs) | |
} | |
/*: | |
Protocol representing types that implement `+` | |
*/ | |
protocol Combinable { | |
static func +(lhs: Self, rhs: Self) -> Self | |
} | |
extension String: Combinable {} | |
/*: | |
Return all combinations of elements of pre with elements of suf | |
Arguments are arrays of `Combinable`. | |
*/ | |
func permute<T: Combinable>(pre:[T], _ suf: [T]) -> [T] { | |
if pre.isEmpty { return suf } | |
if suf.isEmpty { return pre } | |
return pre.flatMap { p in suf.map { s in p + s } } | |
} | |
let keyMap: [Int: [String]] = [ | |
0: ["0"], | |
1: ["1"], | |
2: ["a","b","c"], | |
3: ["d","e","f"], | |
4: ["g","h","i"], | |
5: ["j","k","l"], | |
6: ["m","n","o"], | |
7: ["p","q","r","s"], | |
8: ["t","u","v"], | |
9: ["w","x","y","z"] | |
] | |
/*: | |
1. Characters of the string | |
2. Convert each `Character` to an `Int?` | |
3. Replace each non-nil Int with an array of letters | |
4. Combine permutations of every element | |
5. Optionally, filter by a set of valid En-US words | |
*/ | |
func phoneWords(_ number: String) -> [String] { | |
return number | |
.characters // 1 | |
.flatMap(Int.init) // 2 | |
.flatMap(keyMap |> transform) // 3 | |
.reduce([], permute) // 4 | |
.filter(isWord) // 5 | |
} | |
/*: | |
Similar to `phoneWords(String)` but with a min length | |
*/ | |
func phoneWords(minLength: Int) -> (_ number: String) -> [String] { | |
return { | |
number in | |
if number.characters.filter(("2"..."9").contains).count >= minLength { | |
return phoneWords(number) | |
} else { | |
return [number] | |
} | |
} | |
} | |
/*: | |
1. Characters of the string | |
2. Split at non-digits | |
3. Convert each sub-array into `String` | |
4. Replace each `String` with an array of possible phone words | |
*/ | |
let m = "1-800-3569377" | |
.characters // 1 | |
.split() { return !isDigit(c: $0) } // 2 | |
.map(String.init) // 3 | |
.map(phoneWords(minLength: 2)) // 4 | |
print(m) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment