Dominick
Dominick

Reputation: 174

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

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.

Upvotes: 5

Views: 48754

Answers (3)

logeshpalani31
logeshpalani31

Reputation: 1620

If, it is optional character or string

usedLetters.append(currentWord.randomElement().map(String.init)!)

Here usedLetters is Array[String] currentWord is Optional string

Upvotes: 1

vacawama
vacawama

Reputation: 154513

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"]

Upvotes: 7

sketchyTech
sketchyTech

Reputation: 5906

This line is returning a Character array, not a String one:

var arrayOfLetters = Array(allWords[0])

You can convert this to a String array like so:

var arrayOfLetters = Array(allWords[0]).map{String($0)}

You could alternatively write:

var arrayOfLetters = allWords[0].characters.map{String($0)}

Upvotes: 4

Related Questions