Generating Phone Words in Swift
up vote
5
down vote
favorite
I've been playing around with some basic algorithms in Swift. Here I am trying to generate phone words, words which can be mapped from phone numbers using the characters under each digit. I was trying to use map/filter etc.. as much as possible, do you think the result ended up being more readable or less?
First step, getting the word list ready.
The built-in words file "/usr/share/dict/words" can be used. But it seems to be missing plurals like "flowers".
The "words.txt" file used below can be found at dwyl/english-words.
If you are pasting this into a playground then it's best to put this part in the "Sources" directory so it doesn't get evaluated every time
let words = Set(
try! String(contentsOfURL: NSBundle.mainBundle().URLForResource("words", withExtension: "txt")!)
.componentsSeparatedByCharactersInSet(
NSCharacterSet.newlineCharacterSet()
)
)
public func isWord(s: String) -> Bool {
return words.contains(s)
}
Next, the mapping of keys to characters (array of one-letter strings).
let phoneKeyMap: [Character: [String]] = [
"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"]
]
Some helper functions. These aren't really necessary but I think it makes the last bit of code more readable.
func isPhoneKeyMappable(c: Character) -> Bool {
return ("2"..."9").contains(String(c))
}
func hasMoreThanOne<T: CollectionType>(c: T) -> Bool {
return c.count > 1
}
func filterWith<T: CollectionType>(pred: T.Generator.Element -> Bool)(c: T) -> [T.Generator.Element] {
return c.filter(pred)
}
Generate phone words recursively
- handle empty string
- handle non keypad characters
- termination condition
- recursively build words
- combine words with all characters for cur key
This function expects the passed-in string to have characters "2"..."9".
func phoneWords(s: String) -> [String] {
guard let n = s.characters.first else { return } // 1
guard let px = phoneKeyMap[n] else { return } // 2
if s.characters.count == 1 { return px } // 3
let sx = phoneWords(String(s.characters.dropFirst())) // 4
return px.flatMap { p in sx.map { s in p + s } } // 5
}
Generate phone words for the phone number 1-800-FLOWERS
- split the phone number at "1" and "0"
- filter out digits that are not 2-9
- filter out single-digit words
- convert each collection of
Character
into aString
- convert each string into a collection of words based on keypad
- filter out non-engligh words based on a word dictionary
Finally:
"1-800-356-9377".characters
.split { ("0"..."1").contains(String($0)) } // 1
.map(filterWith(isPhoneKeyMappable)) // 2
.filter(hasMoreThanOne) // 3
.map(String.init) // 4
.map(phoneWords) // 5
.map(filterWith(isWord)) // 6
Edit
I've made some changes, I think this is an improvement. A quick outline of the changes:
- Made the key mapping
[Int: [String]]
instead of[Character: [String]]
. The original version ended up breaking the input into characters then turning them into strings then breaking them back out into characters. This could have just been an array of type[[String]]
but I like the fact that dictionary returns an optional when subscripted. - Removed
isPhoneKeyMappable
. The key mapping handles this by removing nils (viaflatMap
) when converting from digits to array ofString
. - Added some helper methods, renamed other.
phoneWords
has been replaced with a more generalpermute
function which simply returns all the permutations of the subarray items.
Here is the updated code (not including the words
list which hasn't changed):
/*:
This solution involves using a map of `Int` to `String` arrays. `String` arrays are used instead of just strings since we have to split each string into characters and convert back to `String` for concatenation anyway. This could be done as an array since the key is an `Int`, but using a map gives us added safety by returning optionals when subscripting.
*/
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"]
]
/*:
Generate permutations
1. handle empty string
2. termination condition
3. recursively generate permutations on smaller inputs
4. combine prefixes with each result from recursive permutation
*/
func permute(parts: [[String]]) -> [String] {
guard let prefixes = parts.first else { return } // 1
if parts.count == 1 { return prefixes } // 2
let sx = permute(Array(parts.dropFirst(1))) // 3
return prefixes.flatMap { p in sx.map { s in p + s } }
}
/*:
Some helper functions to make things more readable later
*/
func hasMoreThanOne<T: CollectionType>(c: T) -> Bool {
return c.count > 1
}
func filter<T: CollectionType>(pred: T.Generator.Element -> Bool)(c: T) -> [T.Generator.Element] {
return c.filter(pred)
}
func flatMap<T: CollectionType, V>(transform: T.Generator.Element -> V?)(c: T) -> [V] {
return c.flatMap(transform)
}
func transform<T: Hashable, V>(dict: [T:V])(element: T) -> V? {
return dict[element]
}
infix operator |> { precedence 50 associativity left }
public func |> <T,U>(lhs: T, rhs: T -> U) -> U {
return rhs(lhs)
}
extension Int {
init?(c: Character) {
guard let i = Int(String(c)) else { return nil }
self = i
}
}
extension CollectionType where Generator.Element : Equatable {
public func split(separators: Self.Generator.Element...) -> [Self.SubSequence] {
return self.split(isSeparator: separators.contains)
}
}
/*:
Generate phone words for the phone number `1-800-FLOWERS`
1. break the string down into an array of `Character`
2. convert each `Character` into an `Int`
3. split into subarrays of `Int`
4. replace each digit with a list of characters
5. filter out single-digit subarrays
6. generate permutations
7. filter out non-engligh words
*/
let mnemonics = "1-800-356-9377"
.characters // 1
.flatMap(Int.init) // 2
.split(1, 0) // 3
.map(keyMap |> transform |> flatMap) // 4
.filter(hasMoreThanOne) // 5
.map(permute) // 6
.map(isWord |> filter) // 7
print(mnemonics) // [["flowers"]]
swift
add a comment |
up vote
5
down vote
favorite
I've been playing around with some basic algorithms in Swift. Here I am trying to generate phone words, words which can be mapped from phone numbers using the characters under each digit. I was trying to use map/filter etc.. as much as possible, do you think the result ended up being more readable or less?
First step, getting the word list ready.
The built-in words file "/usr/share/dict/words" can be used. But it seems to be missing plurals like "flowers".
The "words.txt" file used below can be found at dwyl/english-words.
If you are pasting this into a playground then it's best to put this part in the "Sources" directory so it doesn't get evaluated every time
let words = Set(
try! String(contentsOfURL: NSBundle.mainBundle().URLForResource("words", withExtension: "txt")!)
.componentsSeparatedByCharactersInSet(
NSCharacterSet.newlineCharacterSet()
)
)
public func isWord(s: String) -> Bool {
return words.contains(s)
}
Next, the mapping of keys to characters (array of one-letter strings).
let phoneKeyMap: [Character: [String]] = [
"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"]
]
Some helper functions. These aren't really necessary but I think it makes the last bit of code more readable.
func isPhoneKeyMappable(c: Character) -> Bool {
return ("2"..."9").contains(String(c))
}
func hasMoreThanOne<T: CollectionType>(c: T) -> Bool {
return c.count > 1
}
func filterWith<T: CollectionType>(pred: T.Generator.Element -> Bool)(c: T) -> [T.Generator.Element] {
return c.filter(pred)
}
Generate phone words recursively
- handle empty string
- handle non keypad characters
- termination condition
- recursively build words
- combine words with all characters for cur key
This function expects the passed-in string to have characters "2"..."9".
func phoneWords(s: String) -> [String] {
guard let n = s.characters.first else { return } // 1
guard let px = phoneKeyMap[n] else { return } // 2
if s.characters.count == 1 { return px } // 3
let sx = phoneWords(String(s.characters.dropFirst())) // 4
return px.flatMap { p in sx.map { s in p + s } } // 5
}
Generate phone words for the phone number 1-800-FLOWERS
- split the phone number at "1" and "0"
- filter out digits that are not 2-9
- filter out single-digit words
- convert each collection of
Character
into aString
- convert each string into a collection of words based on keypad
- filter out non-engligh words based on a word dictionary
Finally:
"1-800-356-9377".characters
.split { ("0"..."1").contains(String($0)) } // 1
.map(filterWith(isPhoneKeyMappable)) // 2
.filter(hasMoreThanOne) // 3
.map(String.init) // 4
.map(phoneWords) // 5
.map(filterWith(isWord)) // 6
Edit
I've made some changes, I think this is an improvement. A quick outline of the changes:
- Made the key mapping
[Int: [String]]
instead of[Character: [String]]
. The original version ended up breaking the input into characters then turning them into strings then breaking them back out into characters. This could have just been an array of type[[String]]
but I like the fact that dictionary returns an optional when subscripted. - Removed
isPhoneKeyMappable
. The key mapping handles this by removing nils (viaflatMap
) when converting from digits to array ofString
. - Added some helper methods, renamed other.
phoneWords
has been replaced with a more generalpermute
function which simply returns all the permutations of the subarray items.
Here is the updated code (not including the words
list which hasn't changed):
/*:
This solution involves using a map of `Int` to `String` arrays. `String` arrays are used instead of just strings since we have to split each string into characters and convert back to `String` for concatenation anyway. This could be done as an array since the key is an `Int`, but using a map gives us added safety by returning optionals when subscripting.
*/
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"]
]
/*:
Generate permutations
1. handle empty string
2. termination condition
3. recursively generate permutations on smaller inputs
4. combine prefixes with each result from recursive permutation
*/
func permute(parts: [[String]]) -> [String] {
guard let prefixes = parts.first else { return } // 1
if parts.count == 1 { return prefixes } // 2
let sx = permute(Array(parts.dropFirst(1))) // 3
return prefixes.flatMap { p in sx.map { s in p + s } }
}
/*:
Some helper functions to make things more readable later
*/
func hasMoreThanOne<T: CollectionType>(c: T) -> Bool {
return c.count > 1
}
func filter<T: CollectionType>(pred: T.Generator.Element -> Bool)(c: T) -> [T.Generator.Element] {
return c.filter(pred)
}
func flatMap<T: CollectionType, V>(transform: T.Generator.Element -> V?)(c: T) -> [V] {
return c.flatMap(transform)
}
func transform<T: Hashable, V>(dict: [T:V])(element: T) -> V? {
return dict[element]
}
infix operator |> { precedence 50 associativity left }
public func |> <T,U>(lhs: T, rhs: T -> U) -> U {
return rhs(lhs)
}
extension Int {
init?(c: Character) {
guard let i = Int(String(c)) else { return nil }
self = i
}
}
extension CollectionType where Generator.Element : Equatable {
public func split(separators: Self.Generator.Element...) -> [Self.SubSequence] {
return self.split(isSeparator: separators.contains)
}
}
/*:
Generate phone words for the phone number `1-800-FLOWERS`
1. break the string down into an array of `Character`
2. convert each `Character` into an `Int`
3. split into subarrays of `Int`
4. replace each digit with a list of characters
5. filter out single-digit subarrays
6. generate permutations
7. filter out non-engligh words
*/
let mnemonics = "1-800-356-9377"
.characters // 1
.flatMap(Int.init) // 2
.split(1, 0) // 3
.map(keyMap |> transform |> flatMap) // 4
.filter(hasMoreThanOne) // 5
.map(permute) // 6
.map(isWord |> filter) // 7
print(mnemonics) // [["flowers"]]
swift
Full code available in a gist
– vopilif
Nov 24 '15 at 23:54
add a comment |
up vote
5
down vote
favorite
up vote
5
down vote
favorite
I've been playing around with some basic algorithms in Swift. Here I am trying to generate phone words, words which can be mapped from phone numbers using the characters under each digit. I was trying to use map/filter etc.. as much as possible, do you think the result ended up being more readable or less?
First step, getting the word list ready.
The built-in words file "/usr/share/dict/words" can be used. But it seems to be missing plurals like "flowers".
The "words.txt" file used below can be found at dwyl/english-words.
If you are pasting this into a playground then it's best to put this part in the "Sources" directory so it doesn't get evaluated every time
let words = Set(
try! String(contentsOfURL: NSBundle.mainBundle().URLForResource("words", withExtension: "txt")!)
.componentsSeparatedByCharactersInSet(
NSCharacterSet.newlineCharacterSet()
)
)
public func isWord(s: String) -> Bool {
return words.contains(s)
}
Next, the mapping of keys to characters (array of one-letter strings).
let phoneKeyMap: [Character: [String]] = [
"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"]
]
Some helper functions. These aren't really necessary but I think it makes the last bit of code more readable.
func isPhoneKeyMappable(c: Character) -> Bool {
return ("2"..."9").contains(String(c))
}
func hasMoreThanOne<T: CollectionType>(c: T) -> Bool {
return c.count > 1
}
func filterWith<T: CollectionType>(pred: T.Generator.Element -> Bool)(c: T) -> [T.Generator.Element] {
return c.filter(pred)
}
Generate phone words recursively
- handle empty string
- handle non keypad characters
- termination condition
- recursively build words
- combine words with all characters for cur key
This function expects the passed-in string to have characters "2"..."9".
func phoneWords(s: String) -> [String] {
guard let n = s.characters.first else { return } // 1
guard let px = phoneKeyMap[n] else { return } // 2
if s.characters.count == 1 { return px } // 3
let sx = phoneWords(String(s.characters.dropFirst())) // 4
return px.flatMap { p in sx.map { s in p + s } } // 5
}
Generate phone words for the phone number 1-800-FLOWERS
- split the phone number at "1" and "0"
- filter out digits that are not 2-9
- filter out single-digit words
- convert each collection of
Character
into aString
- convert each string into a collection of words based on keypad
- filter out non-engligh words based on a word dictionary
Finally:
"1-800-356-9377".characters
.split { ("0"..."1").contains(String($0)) } // 1
.map(filterWith(isPhoneKeyMappable)) // 2
.filter(hasMoreThanOne) // 3
.map(String.init) // 4
.map(phoneWords) // 5
.map(filterWith(isWord)) // 6
Edit
I've made some changes, I think this is an improvement. A quick outline of the changes:
- Made the key mapping
[Int: [String]]
instead of[Character: [String]]
. The original version ended up breaking the input into characters then turning them into strings then breaking them back out into characters. This could have just been an array of type[[String]]
but I like the fact that dictionary returns an optional when subscripted. - Removed
isPhoneKeyMappable
. The key mapping handles this by removing nils (viaflatMap
) when converting from digits to array ofString
. - Added some helper methods, renamed other.
phoneWords
has been replaced with a more generalpermute
function which simply returns all the permutations of the subarray items.
Here is the updated code (not including the words
list which hasn't changed):
/*:
This solution involves using a map of `Int` to `String` arrays. `String` arrays are used instead of just strings since we have to split each string into characters and convert back to `String` for concatenation anyway. This could be done as an array since the key is an `Int`, but using a map gives us added safety by returning optionals when subscripting.
*/
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"]
]
/*:
Generate permutations
1. handle empty string
2. termination condition
3. recursively generate permutations on smaller inputs
4. combine prefixes with each result from recursive permutation
*/
func permute(parts: [[String]]) -> [String] {
guard let prefixes = parts.first else { return } // 1
if parts.count == 1 { return prefixes } // 2
let sx = permute(Array(parts.dropFirst(1))) // 3
return prefixes.flatMap { p in sx.map { s in p + s } }
}
/*:
Some helper functions to make things more readable later
*/
func hasMoreThanOne<T: CollectionType>(c: T) -> Bool {
return c.count > 1
}
func filter<T: CollectionType>(pred: T.Generator.Element -> Bool)(c: T) -> [T.Generator.Element] {
return c.filter(pred)
}
func flatMap<T: CollectionType, V>(transform: T.Generator.Element -> V?)(c: T) -> [V] {
return c.flatMap(transform)
}
func transform<T: Hashable, V>(dict: [T:V])(element: T) -> V? {
return dict[element]
}
infix operator |> { precedence 50 associativity left }
public func |> <T,U>(lhs: T, rhs: T -> U) -> U {
return rhs(lhs)
}
extension Int {
init?(c: Character) {
guard let i = Int(String(c)) else { return nil }
self = i
}
}
extension CollectionType where Generator.Element : Equatable {
public func split(separators: Self.Generator.Element...) -> [Self.SubSequence] {
return self.split(isSeparator: separators.contains)
}
}
/*:
Generate phone words for the phone number `1-800-FLOWERS`
1. break the string down into an array of `Character`
2. convert each `Character` into an `Int`
3. split into subarrays of `Int`
4. replace each digit with a list of characters
5. filter out single-digit subarrays
6. generate permutations
7. filter out non-engligh words
*/
let mnemonics = "1-800-356-9377"
.characters // 1
.flatMap(Int.init) // 2
.split(1, 0) // 3
.map(keyMap |> transform |> flatMap) // 4
.filter(hasMoreThanOne) // 5
.map(permute) // 6
.map(isWord |> filter) // 7
print(mnemonics) // [["flowers"]]
swift
I've been playing around with some basic algorithms in Swift. Here I am trying to generate phone words, words which can be mapped from phone numbers using the characters under each digit. I was trying to use map/filter etc.. as much as possible, do you think the result ended up being more readable or less?
First step, getting the word list ready.
The built-in words file "/usr/share/dict/words" can be used. But it seems to be missing plurals like "flowers".
The "words.txt" file used below can be found at dwyl/english-words.
If you are pasting this into a playground then it's best to put this part in the "Sources" directory so it doesn't get evaluated every time
let words = Set(
try! String(contentsOfURL: NSBundle.mainBundle().URLForResource("words", withExtension: "txt")!)
.componentsSeparatedByCharactersInSet(
NSCharacterSet.newlineCharacterSet()
)
)
public func isWord(s: String) -> Bool {
return words.contains(s)
}
Next, the mapping of keys to characters (array of one-letter strings).
let phoneKeyMap: [Character: [String]] = [
"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"]
]
Some helper functions. These aren't really necessary but I think it makes the last bit of code more readable.
func isPhoneKeyMappable(c: Character) -> Bool {
return ("2"..."9").contains(String(c))
}
func hasMoreThanOne<T: CollectionType>(c: T) -> Bool {
return c.count > 1
}
func filterWith<T: CollectionType>(pred: T.Generator.Element -> Bool)(c: T) -> [T.Generator.Element] {
return c.filter(pred)
}
Generate phone words recursively
- handle empty string
- handle non keypad characters
- termination condition
- recursively build words
- combine words with all characters for cur key
This function expects the passed-in string to have characters "2"..."9".
func phoneWords(s: String) -> [String] {
guard let n = s.characters.first else { return } // 1
guard let px = phoneKeyMap[n] else { return } // 2
if s.characters.count == 1 { return px } // 3
let sx = phoneWords(String(s.characters.dropFirst())) // 4
return px.flatMap { p in sx.map { s in p + s } } // 5
}
Generate phone words for the phone number 1-800-FLOWERS
- split the phone number at "1" and "0"
- filter out digits that are not 2-9
- filter out single-digit words
- convert each collection of
Character
into aString
- convert each string into a collection of words based on keypad
- filter out non-engligh words based on a word dictionary
Finally:
"1-800-356-9377".characters
.split { ("0"..."1").contains(String($0)) } // 1
.map(filterWith(isPhoneKeyMappable)) // 2
.filter(hasMoreThanOne) // 3
.map(String.init) // 4
.map(phoneWords) // 5
.map(filterWith(isWord)) // 6
Edit
I've made some changes, I think this is an improvement. A quick outline of the changes:
- Made the key mapping
[Int: [String]]
instead of[Character: [String]]
. The original version ended up breaking the input into characters then turning them into strings then breaking them back out into characters. This could have just been an array of type[[String]]
but I like the fact that dictionary returns an optional when subscripted. - Removed
isPhoneKeyMappable
. The key mapping handles this by removing nils (viaflatMap
) when converting from digits to array ofString
. - Added some helper methods, renamed other.
phoneWords
has been replaced with a more generalpermute
function which simply returns all the permutations of the subarray items.
Here is the updated code (not including the words
list which hasn't changed):
/*:
This solution involves using a map of `Int` to `String` arrays. `String` arrays are used instead of just strings since we have to split each string into characters and convert back to `String` for concatenation anyway. This could be done as an array since the key is an `Int`, but using a map gives us added safety by returning optionals when subscripting.
*/
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"]
]
/*:
Generate permutations
1. handle empty string
2. termination condition
3. recursively generate permutations on smaller inputs
4. combine prefixes with each result from recursive permutation
*/
func permute(parts: [[String]]) -> [String] {
guard let prefixes = parts.first else { return } // 1
if parts.count == 1 { return prefixes } // 2
let sx = permute(Array(parts.dropFirst(1))) // 3
return prefixes.flatMap { p in sx.map { s in p + s } }
}
/*:
Some helper functions to make things more readable later
*/
func hasMoreThanOne<T: CollectionType>(c: T) -> Bool {
return c.count > 1
}
func filter<T: CollectionType>(pred: T.Generator.Element -> Bool)(c: T) -> [T.Generator.Element] {
return c.filter(pred)
}
func flatMap<T: CollectionType, V>(transform: T.Generator.Element -> V?)(c: T) -> [V] {
return c.flatMap(transform)
}
func transform<T: Hashable, V>(dict: [T:V])(element: T) -> V? {
return dict[element]
}
infix operator |> { precedence 50 associativity left }
public func |> <T,U>(lhs: T, rhs: T -> U) -> U {
return rhs(lhs)
}
extension Int {
init?(c: Character) {
guard let i = Int(String(c)) else { return nil }
self = i
}
}
extension CollectionType where Generator.Element : Equatable {
public func split(separators: Self.Generator.Element...) -> [Self.SubSequence] {
return self.split(isSeparator: separators.contains)
}
}
/*:
Generate phone words for the phone number `1-800-FLOWERS`
1. break the string down into an array of `Character`
2. convert each `Character` into an `Int`
3. split into subarrays of `Int`
4. replace each digit with a list of characters
5. filter out single-digit subarrays
6. generate permutations
7. filter out non-engligh words
*/
let mnemonics = "1-800-356-9377"
.characters // 1
.flatMap(Int.init) // 2
.split(1, 0) // 3
.map(keyMap |> transform |> flatMap) // 4
.filter(hasMoreThanOne) // 5
.map(permute) // 6
.map(isWord |> filter) // 7
print(mnemonics) // [["flowers"]]
swift
swift
edited Nov 25 '15 at 21:13
asked Nov 24 '15 at 23:54
vopilif
1262
1262
Full code available in a gist
– vopilif
Nov 24 '15 at 23:54
add a comment |
Full code available in a gist
– vopilif
Nov 24 '15 at 23:54
Full code available in a gist
– vopilif
Nov 24 '15 at 23:54
Full code available in a gist
– vopilif
Nov 24 '15 at 23:54
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
Here is my version, It Would need, some kind of isWord function to make it useful
You may find it easier to read it from the bottom up
The use of an enum improves readability a bit and makes it easy to change. I think the performance would be the same so the main difference between the solutions is the coding style, which is a matter of preference.
I have not handled the nonnumeric character in the phone number and leave it up to the caller of the routine to remove them. This concentrates on the core functionality.
My solution is agnostic to how many characters if any are mapped to the number which makes it robust.
enum Dialpad : Int {
case zero ,one ,two ,three ,four ,five ,six ,seven ,eight ,nine
var letters : [String] {
switch self {
case .zero,.one:
return
case .two:
return ["a","b","c"]
case .three:
return ["d","e","f"]
case .four:
return ["g","h","i"]
case .five:
return ["j","k","l"]
case .six:
return ["m","n","o"]
case .seven:
return ["p","q","r","s"]
case .eight:
return ["t","u","v"]
case .nine:
return ["w","x","y","z"]
}
}
}
// recursive function which takes in arrays of characters || strings
// and spits out the combinations example ["A","B"],["C","D"] -> ["AC","AD","BC","DE"]
// the output is n*m
func comboArray(_ arrays:[[String]], n:Int,set:inout Set<String>) {
if n >= arrays.count { return }
let array = arrays[n]
if set.isEmpty {
set = Set(array)
} else {
set.forEach { (c1) in
array.forEach({ (c2) in
set.insert(c1+c2)
})
if !array.isEmpty {
set.remove(c1)
}
}
}
comboArray(arrays, n: n+1, set: &set)
}
// takes in a number and maps it to the letters on a phone dialpad
func dialPadLetters(number:Int) -> Set<String> {
let stringNumber = String(number)
var arrayLetter : [Array<String>] =
for c in stringNumber {
let n = Int(String(c))! // back to a number it is safe to force unwrap
let letters = Dialpad(rawValue: n)!.letters
arrayLetter.append(letters)
}
var mySet : Set<String> =
comboArray(arrayLetter, n: 0, set: &mySet)
return mySet
}
let theSet = dialPadLetters(number: 1234)
print(" theset (theSet)")
New contributor
Welcome to code review. Please provide some explanation of why this solution is better. "Alternate solution" answers with no explanation are not very helpful, and may be deleted. See codereview.stackexchange.com/help/how-to-answer
– user673679
yesterday
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
Here is my version, It Would need, some kind of isWord function to make it useful
You may find it easier to read it from the bottom up
The use of an enum improves readability a bit and makes it easy to change. I think the performance would be the same so the main difference between the solutions is the coding style, which is a matter of preference.
I have not handled the nonnumeric character in the phone number and leave it up to the caller of the routine to remove them. This concentrates on the core functionality.
My solution is agnostic to how many characters if any are mapped to the number which makes it robust.
enum Dialpad : Int {
case zero ,one ,two ,three ,four ,five ,six ,seven ,eight ,nine
var letters : [String] {
switch self {
case .zero,.one:
return
case .two:
return ["a","b","c"]
case .three:
return ["d","e","f"]
case .four:
return ["g","h","i"]
case .five:
return ["j","k","l"]
case .six:
return ["m","n","o"]
case .seven:
return ["p","q","r","s"]
case .eight:
return ["t","u","v"]
case .nine:
return ["w","x","y","z"]
}
}
}
// recursive function which takes in arrays of characters || strings
// and spits out the combinations example ["A","B"],["C","D"] -> ["AC","AD","BC","DE"]
// the output is n*m
func comboArray(_ arrays:[[String]], n:Int,set:inout Set<String>) {
if n >= arrays.count { return }
let array = arrays[n]
if set.isEmpty {
set = Set(array)
} else {
set.forEach { (c1) in
array.forEach({ (c2) in
set.insert(c1+c2)
})
if !array.isEmpty {
set.remove(c1)
}
}
}
comboArray(arrays, n: n+1, set: &set)
}
// takes in a number and maps it to the letters on a phone dialpad
func dialPadLetters(number:Int) -> Set<String> {
let stringNumber = String(number)
var arrayLetter : [Array<String>] =
for c in stringNumber {
let n = Int(String(c))! // back to a number it is safe to force unwrap
let letters = Dialpad(rawValue: n)!.letters
arrayLetter.append(letters)
}
var mySet : Set<String> =
comboArray(arrayLetter, n: 0, set: &mySet)
return mySet
}
let theSet = dialPadLetters(number: 1234)
print(" theset (theSet)")
New contributor
Welcome to code review. Please provide some explanation of why this solution is better. "Alternate solution" answers with no explanation are not very helpful, and may be deleted. See codereview.stackexchange.com/help/how-to-answer
– user673679
yesterday
add a comment |
up vote
0
down vote
Here is my version, It Would need, some kind of isWord function to make it useful
You may find it easier to read it from the bottom up
The use of an enum improves readability a bit and makes it easy to change. I think the performance would be the same so the main difference between the solutions is the coding style, which is a matter of preference.
I have not handled the nonnumeric character in the phone number and leave it up to the caller of the routine to remove them. This concentrates on the core functionality.
My solution is agnostic to how many characters if any are mapped to the number which makes it robust.
enum Dialpad : Int {
case zero ,one ,two ,three ,four ,five ,six ,seven ,eight ,nine
var letters : [String] {
switch self {
case .zero,.one:
return
case .two:
return ["a","b","c"]
case .three:
return ["d","e","f"]
case .four:
return ["g","h","i"]
case .five:
return ["j","k","l"]
case .six:
return ["m","n","o"]
case .seven:
return ["p","q","r","s"]
case .eight:
return ["t","u","v"]
case .nine:
return ["w","x","y","z"]
}
}
}
// recursive function which takes in arrays of characters || strings
// and spits out the combinations example ["A","B"],["C","D"] -> ["AC","AD","BC","DE"]
// the output is n*m
func comboArray(_ arrays:[[String]], n:Int,set:inout Set<String>) {
if n >= arrays.count { return }
let array = arrays[n]
if set.isEmpty {
set = Set(array)
} else {
set.forEach { (c1) in
array.forEach({ (c2) in
set.insert(c1+c2)
})
if !array.isEmpty {
set.remove(c1)
}
}
}
comboArray(arrays, n: n+1, set: &set)
}
// takes in a number and maps it to the letters on a phone dialpad
func dialPadLetters(number:Int) -> Set<String> {
let stringNumber = String(number)
var arrayLetter : [Array<String>] =
for c in stringNumber {
let n = Int(String(c))! // back to a number it is safe to force unwrap
let letters = Dialpad(rawValue: n)!.letters
arrayLetter.append(letters)
}
var mySet : Set<String> =
comboArray(arrayLetter, n: 0, set: &mySet)
return mySet
}
let theSet = dialPadLetters(number: 1234)
print(" theset (theSet)")
New contributor
Welcome to code review. Please provide some explanation of why this solution is better. "Alternate solution" answers with no explanation are not very helpful, and may be deleted. See codereview.stackexchange.com/help/how-to-answer
– user673679
yesterday
add a comment |
up vote
0
down vote
up vote
0
down vote
Here is my version, It Would need, some kind of isWord function to make it useful
You may find it easier to read it from the bottom up
The use of an enum improves readability a bit and makes it easy to change. I think the performance would be the same so the main difference between the solutions is the coding style, which is a matter of preference.
I have not handled the nonnumeric character in the phone number and leave it up to the caller of the routine to remove them. This concentrates on the core functionality.
My solution is agnostic to how many characters if any are mapped to the number which makes it robust.
enum Dialpad : Int {
case zero ,one ,two ,three ,four ,five ,six ,seven ,eight ,nine
var letters : [String] {
switch self {
case .zero,.one:
return
case .two:
return ["a","b","c"]
case .three:
return ["d","e","f"]
case .four:
return ["g","h","i"]
case .five:
return ["j","k","l"]
case .six:
return ["m","n","o"]
case .seven:
return ["p","q","r","s"]
case .eight:
return ["t","u","v"]
case .nine:
return ["w","x","y","z"]
}
}
}
// recursive function which takes in arrays of characters || strings
// and spits out the combinations example ["A","B"],["C","D"] -> ["AC","AD","BC","DE"]
// the output is n*m
func comboArray(_ arrays:[[String]], n:Int,set:inout Set<String>) {
if n >= arrays.count { return }
let array = arrays[n]
if set.isEmpty {
set = Set(array)
} else {
set.forEach { (c1) in
array.forEach({ (c2) in
set.insert(c1+c2)
})
if !array.isEmpty {
set.remove(c1)
}
}
}
comboArray(arrays, n: n+1, set: &set)
}
// takes in a number and maps it to the letters on a phone dialpad
func dialPadLetters(number:Int) -> Set<String> {
let stringNumber = String(number)
var arrayLetter : [Array<String>] =
for c in stringNumber {
let n = Int(String(c))! // back to a number it is safe to force unwrap
let letters = Dialpad(rawValue: n)!.letters
arrayLetter.append(letters)
}
var mySet : Set<String> =
comboArray(arrayLetter, n: 0, set: &mySet)
return mySet
}
let theSet = dialPadLetters(number: 1234)
print(" theset (theSet)")
New contributor
Here is my version, It Would need, some kind of isWord function to make it useful
You may find it easier to read it from the bottom up
The use of an enum improves readability a bit and makes it easy to change. I think the performance would be the same so the main difference between the solutions is the coding style, which is a matter of preference.
I have not handled the nonnumeric character in the phone number and leave it up to the caller of the routine to remove them. This concentrates on the core functionality.
My solution is agnostic to how many characters if any are mapped to the number which makes it robust.
enum Dialpad : Int {
case zero ,one ,two ,three ,four ,five ,six ,seven ,eight ,nine
var letters : [String] {
switch self {
case .zero,.one:
return
case .two:
return ["a","b","c"]
case .three:
return ["d","e","f"]
case .four:
return ["g","h","i"]
case .five:
return ["j","k","l"]
case .six:
return ["m","n","o"]
case .seven:
return ["p","q","r","s"]
case .eight:
return ["t","u","v"]
case .nine:
return ["w","x","y","z"]
}
}
}
// recursive function which takes in arrays of characters || strings
// and spits out the combinations example ["A","B"],["C","D"] -> ["AC","AD","BC","DE"]
// the output is n*m
func comboArray(_ arrays:[[String]], n:Int,set:inout Set<String>) {
if n >= arrays.count { return }
let array = arrays[n]
if set.isEmpty {
set = Set(array)
} else {
set.forEach { (c1) in
array.forEach({ (c2) in
set.insert(c1+c2)
})
if !array.isEmpty {
set.remove(c1)
}
}
}
comboArray(arrays, n: n+1, set: &set)
}
// takes in a number and maps it to the letters on a phone dialpad
func dialPadLetters(number:Int) -> Set<String> {
let stringNumber = String(number)
var arrayLetter : [Array<String>] =
for c in stringNumber {
let n = Int(String(c))! // back to a number it is safe to force unwrap
let letters = Dialpad(rawValue: n)!.letters
arrayLetter.append(letters)
}
var mySet : Set<String> =
comboArray(arrayLetter, n: 0, set: &mySet)
return mySet
}
let theSet = dialPadLetters(number: 1234)
print(" theset (theSet)")
New contributor
edited yesterday
New contributor
answered yesterday
Ryan Heitner
1011
1011
New contributor
New contributor
Welcome to code review. Please provide some explanation of why this solution is better. "Alternate solution" answers with no explanation are not very helpful, and may be deleted. See codereview.stackexchange.com/help/how-to-answer
– user673679
yesterday
add a comment |
Welcome to code review. Please provide some explanation of why this solution is better. "Alternate solution" answers with no explanation are not very helpful, and may be deleted. See codereview.stackexchange.com/help/how-to-answer
– user673679
yesterday
Welcome to code review. Please provide some explanation of why this solution is better. "Alternate solution" answers with no explanation are not very helpful, and may be deleted. See codereview.stackexchange.com/help/how-to-answer
– user673679
yesterday
Welcome to code review. Please provide some explanation of why this solution is better. "Alternate solution" answers with no explanation are not very helpful, and may be deleted. See codereview.stackexchange.com/help/how-to-answer
– user673679
yesterday
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f111758%2fgenerating-phone-words-in-swift%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Full code available in a gist
– vopilif
Nov 24 '15 at 23:54