Migration from Swift 3 to Swift 4 - Cannot Convert String to Expected String.Element

Migration from swift 3 to swift 4 - Cannot convert String to expected String.Element

If you have an Item type with a non optional productID property of type String like this

struct Item {
let productID: String
}

And you have an array of Item

let allItems: [Item] = ...

Then you can get an array of productID(s) using the map method

let productIDs = allItems.map { $0.productID }

Now productIDs is [String].

Swift Error Cannot convert value of type '[String.Element]' (aka 'ArrayCharacter') to expected argument type '[String]'

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

Swift 4.1 - Cannot convert value of type [Character] to [String]

The same behavior can be observed in the following code:

let services: [[String: Any]?] = [
["service1": "service1-name"],
["service2": "service2-name"]
]

let result = services
.flatMap({ $0 })
.flatMap({ $0.1 as! String })
print(result)

I think this is caused by the multiple changes in String and Dictionary in Swift 4 (String becoming a Collection of characters for example). In the code above the first flatMap merges (flattens) the dictionaries into one dictionary and the second flatMap takes every value as a String and flattens them as a 2D Collection of Character.

I think you want something like this:

let result = services
.compactMap { $0 } // remove nil dictionaries
.flatMap { // take all dictionary values as strings and flatten them to an array
$0.values.map { $0.stringValue }
}
print(result)

This line gives an array of strings, expected results

let services = json["services"]
.arrayValue
.flatMap { $0.arrayValue }
.map { $0.stringValue }

Swift error: Cannot convert value of type 'Character' to expected argument type 'Unicode.Scalar'

You can use collection's method func drop(while predicate: (Character) throws -> Bool) rethrows -> Substring while the string "aeiou" does not contain character and return a Substring:

func shortName(from name: String) -> String { name.drop{ !"aeiou".contains($0) }.lowercased() }

shortName(from: "Brian") // "ian"
shortName(from: "Bill") // "ill"

Regarding the issues in your code check the comments through the code bellow:

func shortName(from name: String) -> String {
// you can use a string instead of a CharacterSet to fix your first error
let vowels = "aeiou"
// to fix your second error you can create a variable from your first parameter name
var name = name
// you can iterate through each character using `for character in name`
for character in name {
// check if the string with the vowels contain the current character
if vowels.contains(character) {
// and remove the first character from your name using `removeFirst` method
name.removeFirst()
}
}
// return the resulting name lowercased
return name.lowercased()
}

shortName(from: "Brian") // "ian"

Swift find the end index of a word within a string

Think in ranges and bounds, lastIndex(of expects a single Character

var bigString = "This is a big string containing the pattern"
let pattern = "containing" //random word that is inside big string
if let rangeOfPattern = bigString.range(of: pattern) {
let newText = String(bigString[rangeOfPattern.upperBound...])
bigString = newText // bigString should now be " the pattern"
}

Cannot Convert Value Of Type String To Expected Element Type

You need to do this for declaring an array.

let userArray: NSArray = ["profilePicture", "name", "description", "cityState"]

Try this.



Related Topics



Leave a reply



Submit