I am trying to create an array of letters from a given word by using the following Swift code (I have an array of words for allWords, but for simplicity I've just added an example word there for now):
let allWords = ["Leopards"]
var arrayOfLetters = Array(allWords[0])
let everyPossibleArrangementOfLetters = permute(list: arrayOfLetters)
func permute(list: [String], minStringLen: Int = 3) -> Set<String> {
func permute(fromList: [String], toList: [String], minStringLen: Int, set: inout Set<String>) {
if toList.count >= minStringLen {
set.insert(toList.joined(separator: ""))
}
if !fromList.isEmpty {
for (index, item) in fromList.enumerated() {
var newFrom = fromList
newFrom.remove(at: index)
permute(fromList: newFrom, toList: toList + [item], minStringLen: minStringLen, set: &set)
}
}
}
var set = Set<String>()
permute(fromList: list, toList:[], minStringLen: minStringLen, set: &set)
return set
}
I obtained this code from: Calculate all permutations of a string in Swift
But the following error is presented: Cannot convert value of type '[String.Element]' (aka 'Array') to expected argument type '[String]'
I attempted the following, which works, but it takes over 10 seconds per word (depending on number of repeat letters) and I was hoping to find a better solution.
var arrayOfLetters: [String] = []
for letter in allWords[0] {
arrayOfLetters.append(String(letter))
}
let everyPossibleArrangementOfLetters = permute(list: arrayOfLetters)
I wasn't able to get the following solution to work, although I think is has promise I couldn't get past the productID name of items in the array whereas my array items aren't named... Migration from swift 3 to swift 4 - Cannot convert String to expected String.Element
I'm also creating another array and checking each of those words to ensure their validity, and I run into the same error which I correct in the same way with array.append which is adding a lot more time in that location as well.
var everyPossibleArrangementOfLettersPartDeux: [String] = []
for word in everyPossibleArrangementOfLetters {
everyPossibleArrangementOfLettersPartDeux.append(word)
}
numberOfRealWords = possibleAnagrams(wordArray: everyPossibleArrangementOfLettersPartDeux)
func possibleAnagrams(wordArray: [String]) -> Int {
func isReal(word: String) -> Bool {
let checker = UITextChecker()
let range = NSMakeRange(0, word.utf16.count)
let misspelledRange = checker.rangeOfMisspelledWord(in: word, range: range, startingAt: 0, wrap: false, language: "en")
return misspelledRange.location == NSNotFound
}
var count = 0
for word in wordArray {
if isReal(word: word) {
count += 1
//print(word)
}
}
return count
}
I'm hoping the same replacement for array.append will work in both spots.
The problem is that Array(allWords[0])
produces [Character]
and not the [String]
that you need.
You can call map
on a String
(which is a collection of Character
s and use String.init
on each character to convert it to a String
). The result of the map
will be [String]
:
var arrayOfLetters = allWords[0].map(String.init)
Notes:
Fatal error: Only BidirectionalCollections can be advanced by a negative amount
. This seems to be a Playground issue, because it works correctly in an app."Leopards"
produces 109,536
permutations.Another Approach
Another approach to the problem is to realize that permute
doesn't have to work on [String]
. It could use [Character]
instead. Also, since you are always starting with a String
, why not pass that string to the outer permute
and let it create the [Character]
for you.
Finally, since it is logical to think that you might just want anagrams of the original word, make minStringLen
an optional with a value of nil
and just use word.count
if the value is not specified.
func permute(word: String, minStringLen: Int? = nil) -> Set<String> {
func permute(fromList: [Character], toList: [Character], minStringLen: Int, set: inout Set<String>) {
if toList.count >= minStringLen {
set.insert(String(toList))
}
if !fromList.isEmpty {
for (index, item) in fromList.enumerated() {
var newFrom = fromList
newFrom.remove(at: index)
permute(fromList: newFrom, toList: toList + [item], minStringLen: minStringLen, set: &set)
}
}
}
var set = Set<String>()
permute(fromList: Array(word), toList:[], minStringLen: minStringLen ?? word.count, set: &set)
return set
}
Examples:
print(permute(word: "foo", minStringLen: 1))
["of", "foo", "f", "fo", "o", "oof", "oo", "ofo"]
print(permute(word: "foo"))
["foo", "oof", "ofo"]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With