How to use compact map on custom type? - swift

I am about reduce code by using compact map. But I can't convert custom struct into [String: String] type.
struct Sample {
let key: String
let value: String
}
let all = [Sample]()
I want to make array all samples into dictionary. So I used compact map & It returns error
Cannot convert value of type '[[String : String]]' to specified type
'[String : String]'
But I don't know exactly what I need to use.
let dictionary: [String: String] = all.compactMap{[$0.key: $0.value]}
Please help me to find out correct solutions. Thank you all in advance...

You can use .reduce(into:_:):
let dictionary = all.reduce(into: [:]) { dict, elem in
dict[elem.key] = elem.value
}

Related

Swift Userdefaults converting String to __NSCFString

I have code that save a dictionary of [String: Any] in UserDefaults. On retrieval String are changed to __NSCFString. I am using Mixpanel to track events and sends this dictionary as events properties. Now the problem is __NSCFString is not a valid MixpanelType so Mixpanel is discarding my dictionary.
Questions:
Is there a way to get same datatypes that are saved using dictionary in UserDefaults?
Is there a way Mixpanel accepts converted datatypes?
Here is a code I am using
var mixpanelProperties: [String: Any] {
get { defaults.dictionary(forKey: "\(#function)") ?? [:] }
set { defaults.set(newValue, forKey: "\(#function)") }
}
mixpanelProperties = ["a-key": "value for the key"]
let prop = mixpanelProperties
print("Type of: \(String(describing: prop["a-key"]))")
asdad
MacOS and iOS use a variety of different classes to represent strings, which are all compatible. x as? String should just work, no matter what the concrete class of x is. Unless you use code that explicitely checks the class which you shouldn't do.

What is the return type of JSONSerialization.jsonObject(with:options:) in Swift?

I made the json parser in swift language.
But, many of people are using like below.
let jsonParsed = JSONSerialization.jsonObject(with: data, options: [])
guard let jsonDict = jsonParsed as? Dictionary<String, AnyObject> else { return }
...
Then, I wonder the type of jsonParsed. The JSONSerialization.jsonObject(with:options:) function reference describes that the result type is just Any.
I know the type is Dictionary because JSON. The KEY is String type but, VALUE is AnyObject? How about Any?
I know the difference between AnyObject and Any. Any also includes value type, function type.
Number is also value type in swift: Int, Float, Double...
Is that impossible return type is value type?
Json can be array also. This is valid josn
[
"1",
"2",
"3"
]
You can use this site to verify [https://jsoneditoronline.org/][1].
When you give fragmentsallowed option in the function json result can be Int,Float or any other primitive data type.
So it is not possible to return type in compile time. At run time it is possible. But return type is decided at run time.

Sort Dictionary Alphabetically Cannot assign value of type '[(key: String, value: AnyObject)]' to type 'Dictionary<String, AnyObject>?'

I have this Dictionary, which I am getting from a web service:
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! Dictionary<String, AnyObject>
and now I am trying to sort them alphabetically like so:
self.appDelegate.communityArray = json.sorted(by: {$0.0 < $1.0})
But I get this error:
Cannot assign value of type '[(key: String, value: AnyObject)]' to
type 'Dictionary?'
What am I doing wrong?
This is how I am defining communityArray:
var communityArray: Dictionary<String, AnyObject>?
As mentioned in the comments a dictionary – a collection type containing key-value pairs – is unordered by definition, it cannot be sorted.
The sorted function of collection applied to a dictionary treats the dictionary for example
["foo" : 1, "bar" : false]
as an array of tuples
[(key : "foo", value : 1), (key : "bar", value : false)]
and sorts them by key (.0) or value (.1) (I suspect sorting by value Any will raise a compiler error)
The error occurs because you cannot assign an array of tuples to a variable declared as dictionary. That's almost the literal error message.
As a compromise I recommend to map the dictionary to a custom struct (similar to a tuple but better to handle)
struct Community {
let key : String
let value : Any
}
Your variable name already implies that you want a real array
var communityArray = [Community]()
let json = try JSONSerialization.jsonObject(with: data!) as! Dictionary<String, Any>
communityArray = json.map { Community(key: $0.0, value: $0.1 }.sorted { $0.key < $1.key }
sorted(by:) Returns the elements of the sequence, sorted using the given predicate as the comparison between elements, so you can not use as a dictionary.
For more info about this function you may read sorted(by:) documentation

Swift Dictionary access value through subscript throws Error

Accessing a Swift Dictionary value through subscript syntax is gives error Ambiguous reference to member 'subscript'
Here is the code
class Model {
struct Keys {
static let type :String = "type" //RowType
static let details :String = "details"
}
var type :RowType = .None
var details :[Detail] = []
init(with dictionary:Dictionary<String, Any>) {
if let type = dictionary[Keys.type] as? String {
self.type = self.rowTypeFromString(type: type)
}
if let detailsObj = dictionary[Keys.details] as? Array { //Error : Ambiguous reference to member 'subscript'
}
}
}
if i remove the type casting as? Array at the end of optional-binding it compiles fine
I am expecting the value of details key to be an Array, I know that i can use [String,Any] instead of Dictionary<Key, Value>, What is causing the issue ?
Array doesn't work like NSArray, you explicitly need to tell what type your array is storing.
If you want to store Detail objects in it, the proper syntax is Array<Detail> or simply [Detail]
if let detailsObj = dictionary[Keys.details] as? Array<Detail> {
}
Issue is solved by explicitly specifying the Type of objects the array contains, In my case it was Array<[String:Any]>
if let detailsObj = dictionary[Keys.details] as? Array<[String:Any]> { //we should also specify what type is present inside Array
}
Credits: #Hamish, #Dávid Pásztor
Thanks!

type 'Any' has no subscript members

let employerName = snapshot.value! ["employerName"] as! String
let employerImage = snapshot.value! ["employerImage"] as! String
let uid = snapshot.value! ["uid"] as! String
I reviewed previous posts but cannot seem to find a way to solve this problem. All three lines of code give the "type 'Any' has no subscript members" error. Fairly new to this so any help is appreciated.
snapshot.value has a type of Any. A subscript is a special kind of function that uses the syntax of enclosing a value in braces. This subscript function is implemented by Dictionary.
So what is happening here is that YOU as the developer know that snapshot.value is a Dictionary, but the compiler doesn't. It won't let you call the subscript function because you are trying to call it on a value of type Any and Any does not implement subscript. In order to do this, you have to tell the compiler that your snapshot.value is actually a Dictionary. Further more Dictionary lets you use the subscript function with values of whatever type the Dictionary's keys are. So you need to tell it you have a Dictionary with keys as String(AKA [String: Any]). Going even further than that, in your case, you seem to know that all of the values in your Dictionary are String as well, so instead of casting each value after you subscript it to String using as! String, if you just tell it that your Dictionary has keys and values that are both String types (AKA [String: String]), then you will be able to subscript to access the values and the compiler will know the values are String also!
guard let snapshotDict = snapshot.value as? [String: String] else {
// Do something to handle the error
// if your snapshot.value isn't the type you thought it was going to be.
}
let employerName = snapshotDict["employerName"]
let employerImage = snapshotDict["employerImage"]
let uid = snapshotDict["fid"]
And there you have it!
Since you want to treat snapshot.value as an unwrapped dictionary, try casting to one and, if it succeeds, use that dictionary.
Consider something like:
func findElements(candidate: Any) {
if let dict: [String : String] = candidate as? Dictionary {
print(dict["employerName"])
print(dict["employerImage"])
print(dict["uid"])
}
}
// Fake call
let snapshotValue = ["employerName" : "name", "employerImage" : "image", "uid" : "345"]
findElements(snapshotValue)