Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Error Cannot convert value of type '[String.Element]' (aka 'Array<Character>') to expected argument type '[String]'

Tags:

arrays

swift

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.

like image 561
Dominick Avatar asked Dec 18 '22 23:12

Dominick


1 Answers

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 Characters 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:

  1. When I tried this in a Playground, I was getting the mysterious message 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.
  2. Just the word "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"]
like image 134
vacawama Avatar answered May 23 '23 15:05

vacawama