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 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:
- 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. - Just the word
"Leopards"
produces109,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
How to Synchronize Coredata with Webservices in Swift
JSONserialization.JSONobject Performance in Swift
Swiftui Navigation: How to Switch Detail View to a Different Item
Format Println Output in a Table
How to Cancel Firebase Setvalue While Pending for Completion (When Offline)
Is It Safe to Force Unwrap an Optional After Checking It Is Not Nil
How to Add Detect Button Presses in Tvos
Change the Font of a Datepicker
Swift Ui: Center Text into Circle
When to Call Activatesession() on Wcsession Object
Skspritenode Gets Hidden Below Parent Node
Differences Between Filtering Realm with Nspredicate and Block
Swift Generic Constraints in Init
Phase 1 and Phase 2 Initialization in Swift
Swiftui Share Sheet Crashes iPad