Swift filter function - swift

I am trying to remove null value for key in dictionary
so I have this kind of data:
let dic = ["FirstName": "Anvar", "LastName": "Azizov", "Website": NSNull(),"About": NSNull()]
let array = [dic,2,3,4]
let jsonResult:[String: AnyObject] = ["FirstName": "Anvar", "LastName": "Azizov", "Website": array,"About": NSNull()]
let jsonCleanDictionary = filter(jsonResult, {!($0.1 is NSNull)})
can not understand syntax of above filter function

Do not use NSNull() in swift instead prefer using nil. Further, since its a dictionary adding keys with a null value is pretty useless since dictionaries will return nil if the key doesn't exist. So when checking for null all you have to do is
if let some = dic["key"] as? Value {
// some now contains the value inside dic's key as a value type of Value.
}
Also the filter function works by taking a block which returns a bool so:
dict.filter { (key, value) -> Bool in
// Do stuff to check key and value and return a
// bool which is true if you want that key, value pair to
// appear in the filtered result.
}
In swift closure arguments can get anonymous names if not explicitly return. These names are of the format $0, $1, etc. Now, the filter function takes only parameter specifically the Self.Generator.Element from the CollectionType protocol. For dictionaries this is a tuple containing the key and the value. To access members of unnamed tuples you use .0, .1, .2, etc. depending on the index of the tuple member. So for dictionaries Self.Generator.Element is a tuple containing the key and the value. So $0.1 refers to the value of the key,value pair. Hope this clears this weird syntax up a little bit.

Related

Map dictionary to array to string

I'm handling a dictionary which I need to parse into a string to create a property for a GraphQL mutation.
My dictionary is [String: Bool] and I need to extract the keys set to true.
let dict: [String: Bool] = ["Objct1": true, "Objct2": false, "Objct3": true]
Currently I'm using four functions (filter, enumerate, map and join) and, although I get the desired result, I wonder if I need all of them:
let string = dict.filter { $0.value }
.enumerated()
.map {
return $0.offset == 0
? "\"\($0.element.key)\""
: ", \"\($0.element.key)\""
}
.joined()
Edit:
The final string needs to be wrapped in ": ""Objct1", "Objct3""
You can use a single compactMap, since first you'd need to filter your Dictionary to only keep the true values, then you'd need to map to return the key corresponding to the true values. However, you can always merge consequent filter and map calls into a single compactMap, since compactMap only keeps non-nil values, so instead of returning a boolean as you would for filter, in case your condition evaluates to true, you return whatever you would return in map, otherwise you return nil.
let trueKeys = dict.compactMap({key, value in value ? key : nil})
To join the keys into a single String, you can just call joined on the result of compactMap.
let graphQueryString = dict.compactMap({key, value in value ? "\"\(key)\"" : nil}).joined(separator: ",") // ""Objct3","Objct1""
Keep in mind that the ordering of your keys won't necessarily be the same as you declared the Dictionary, since Dictionary is an unordered collection by definition. If you want to keep ordering, you can use an array of tuples instead of a Dictionary, where the tuple will consist of the key-value pairs.

accessing keys from a returned sorted array of dictionaries in Swift 4

I have an array of dictionaries called groupedDictionary defined below:
// The type is [String : [SingleRepository]]
let groupedDictionary = Dictionary(grouping: finalArrayUnwrapped) { (object) -> String in
var language = "Not Known to GitHub"
if let languageUnwrapped = object.language {
language = languageUnwrapped
}
return language
}
I can easily get all the keys as follows:
let keys = groupedDictionary.keys
However, when I try to sort this array using sorted(by:) in Swift 4, I successfully get the sorted array back with the type [(key: String, value: [SingleRepository])].
// the type is [(key: String, value: [SingleRepository])]
let sortedGroupedDictionary = groupedDictionary.sorted(by: { ($0.value.count) > ($1.value.count) })
How can I get all of the keys from sortedGroupedDictionary?
It is not possible to call ".keys" on sortedGroupedDictionary, since it has a different type.
Please note: I'm not trying to sort the array based on the keys. I did sort the array that consists of dictionaries, based on a predicate which is size of the array containing each value, now I just want to extract the keys.
The method Dictionary.sorted(by:) returns the keys and values of your original dictionary as an array of key-value pairs, sorted by the predicate you pass as an argument. That means that the first element of each tuple is the key you're looking for.
You can go through the result like this:
for (key, value) in sortedGroupedDictionary {
// handle this key-value-pair
}
If all you need is an array of the sorted keys, you can get that using
sortedGroupedDictionary.map { $0.key }

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

Why I get optional value if I didn't mark it as optional [duplicate]

class X {
static let global: [String:String] = [
"x":"x data",
"y":"y data",
"z":"z data"
]
func test(){
let type = "x"
var data:String = X.global[type]!
}
}
I'm getting the error: Value of optional type 'String?' not unwrapped.
Why do I need to use ! after X.global[type]? I'm not using any optional in my dictionary?
Edited:
Even if X.global[type] may not exist for the type, force unwrapping will still crash on runtime. A better approach may be:
if let valExist = X.global[type] {
}
but Xcode is giving me the wrong idea by hinting about optional type.
Dictionary accessor returns optional of its value type because it does not "know" run-time whether certain key is there in the dictionary or not. If it's present, then the associated value is returned, but if it's not then you get nil.
From the documentation:
You can also use subscript syntax to retrieve a value from the dictionary for a particular key. Because it is possible to request a key for which no value exists, a dictionary’s subscript returns an optional value of the dictionary’s value type. If the dictionary contains a value for the requested key, the subscript returns an optional value containing the existing value for that key. Otherwise, the subscript returns nil...
In order to handle the situation properly you need to unwrap the returned optional.
There are several ways:
Option 1:
func test(){
let type = "x"
if var data = X.global[type] {
// Do something with data
}
}
Option 2:
func test(){
let type = "x"
guard var data = X.global[type] else {
// Handle missing value for "type", then either "return" or "break"
}
// Do something with data
}
Option 3:
func test(){
let type = "x"
var data = X.global[type] ?? "Default value for missing keys"
}
If we look at the Dictionary implementation, subscript is returning a ValueType as optional because it doesn't know if the key is exists or not:
//Reading a key that is not present in `self` yields `nil`.
//Writing `nil` as the value for a given key erases that key from `self`.
subscript (key: KeyType) -> ValueType?
So when we try to get a value from our Dictionary we get it as an optional from the subscript; that is we have to unwrap the optional to get the underlying object. As mentioned in earlier answers, option2 is preferred.
guard var data = X.global[type] else {
//key = 'type' doesn't exists
}
//key exists so do something with 'data'

Why do I still need to unwrap Swift dictionary value?

class X {
static let global: [String:String] = [
"x":"x data",
"y":"y data",
"z":"z data"
]
func test(){
let type = "x"
var data:String = X.global[type]!
}
}
I'm getting the error: Value of optional type 'String?' not unwrapped.
Why do I need to use ! after X.global[type]? I'm not using any optional in my dictionary?
Edited:
Even if X.global[type] may not exist for the type, force unwrapping will still crash on runtime. A better approach may be:
if let valExist = X.global[type] {
}
but Xcode is giving me the wrong idea by hinting about optional type.
Dictionary accessor returns optional of its value type because it does not "know" run-time whether certain key is there in the dictionary or not. If it's present, then the associated value is returned, but if it's not then you get nil.
From the documentation:
You can also use subscript syntax to retrieve a value from the dictionary for a particular key. Because it is possible to request a key for which no value exists, a dictionary’s subscript returns an optional value of the dictionary’s value type. If the dictionary contains a value for the requested key, the subscript returns an optional value containing the existing value for that key. Otherwise, the subscript returns nil...
In order to handle the situation properly you need to unwrap the returned optional.
There are several ways:
Option 1:
func test(){
let type = "x"
if var data = X.global[type] {
// Do something with data
}
}
Option 2:
func test(){
let type = "x"
guard var data = X.global[type] else {
// Handle missing value for "type", then either "return" or "break"
}
// Do something with data
}
Option 3:
func test(){
let type = "x"
var data = X.global[type] ?? "Default value for missing keys"
}
If we look at the Dictionary implementation, subscript is returning a ValueType as optional because it doesn't know if the key is exists or not:
//Reading a key that is not present in `self` yields `nil`.
//Writing `nil` as the value for a given key erases that key from `self`.
subscript (key: KeyType) -> ValueType?
So when we try to get a value from our Dictionary we get it as an optional from the subscript; that is we have to unwrap the optional to get the underlying object. As mentioned in earlier answers, option2 is preferred.
guard var data = X.global[type] else {
//key = 'type' doesn't exists
}
//key exists so do something with 'data'