How to set an Array<Object> inside a Dictionary<String, AnyObject> - Swift3 - swift3

I'm new in swift. I'm trying to add an Array to a specific key in my Dictionary.
I have the following code:
var myArray : Array<Links> = []
var myDict : Dictionary<String, AnyObject> = [:]
myDict["links"] = myArray as AnyObject? // I need help in this row, It does not work.
This is the Json structure I have in myDict and I'm trying to set:
id : "blabla"
links: [
0: {key1: "a", key2: "b", name: "c", link: "d"}
1: {key1: "e", key2: "f", name: "j", link: "h"}
]
Please, consider I already have all the rest working properly. My only problem is how to add my array in the dictionary as commented in the code above.
My JSON structure:
I hope I could make myself clear enough.
Thank you.

First of all don't cast types up and don't annotate types unless the compiler complains.
Second of all a JSON dictionary is [String:Any] in Swift 3.
Further the recommended syntax to create an empty collection object is
var myDict = Dictionary<String, Any>()
Assuming your array – actually a dictionary – is
let myArray = [
0: ["key1": "a", "key2": "b", "name": "c", "link": "d"],
1: ["key1": "e", "key2": "f", "name": "j", "link": "h"]
]
just assign it:
myDict["links"] = myArray
Even if there is a struct
struct Link {
var key1, key2, name, link : String
}
and the array dictionary is
let linkDictionary = [
0: Link(key1:"a", key2: "b", name: "c", link: "d"),
1: Link(key1:"e", key2: "f", name: "g", link: "h")]
you can assign it if the value type is Any
myDict["links"] = linkDictionary

Assuming, for a second, that links really was an array, it would be:
var dictionary: [String: Any] = [
"id": "blabla",
"links": [
["key1": "a", "key2": "b", "name": "c", "link": "d"],
["key1": "e", "key2": "f", "name": "j", "link": "h"]
]
]
// retrieve links, or initialize it if not found
var links = dictionary["links"] as? [[String: String]] ?? [[String: String]]()
// add your new link to local dictionary
links.append(["key1": "k", "key2": "l", "name": "m", "link": "n"])
// update original structure
dictionary["links"] = links
Personally, though, when I see a repeating dictionary structure like your links, this screams for a real model for these objects. For example:
struct Foo {
let id: String
var links: [Link]?
}
struct Link {
let key1: String
let key2: String
let name: String
let link: String
}
var foo = Foo(id: "blabla", links: [
Link(key1: "a", key2: "b", name: "c", link: "d"),
Link(key1: "e", key2: "f", name: "j", link: "h")
])
foo.links?.append(Link(key1: "k", key2: "l", name: "m", link: "n"))
Now, in this latter example, I assumed that links was really an array, not a dictionary, but that's not really my point here. My key observation is that code is more readable and robust if you use proper custom types rather than just arrays and dictionaries.
And if you need to send and receive these model objects to some web service, you then map this model object to and from JSON. But use custom types for your actual model.
If you want to make the above types easily converted to and from JSON, you can use one of the object mapping libraries out there, so you can do something yourself, e.g.:
protocol Jsonable {
var jsonObject: Any { get }
init?(jsonObject: Any)
}
extension Foo: Jsonable {
var jsonObject: Any {
return [
"id": id,
"links": links?.map { $0.jsonObject } ?? [Any]()
]
}
init?(jsonObject: Any) {
guard let dictionary = jsonObject as? [String: Any],
let id = dictionary["id"] as? String else { return nil }
var links: [Link]?
if let linksDictionary = dictionary["links"] as? [Any] {
links = linksDictionary.map { Link(jsonObject: $0)! }
}
self.init(id: id, links: links)
}
}
extension Link: Jsonable {
var jsonObject: Any { return [ "key1": key1, "key2": key2, "name": name, "link": link ] }
init?(jsonObject: Any) {
guard let dictionary = jsonObject as? [String: Any],
let key1 = dictionary["key1"] as? String,
let key2 = dictionary["key2"] as? String,
let name = dictionary["name"] as? String,
let link = dictionary["link"] as? String else {
return nil
}
self.init(key1: key1, key2: key2, name: name, link: link)
}
}
Then you can do stuff like:
let object = try JSONSerialization.jsonObject(with: data)
var foo = Foo(jsonObject: object)!
Or:
foo.links?.append(Link(key1: "j", key2: "k", name: "l", link: "m"))
let data = try! JSONSerialization.data(withJSONObject: foo.jsonObject)

This was the solution:
var arrLinks : Array<Dictionary<String, Any>> = []
for link in myArray {
var dict : Dictionary<String, Any> = [:]
dict["key1"] = link.name
dict["key2"] = link.ghostBefore
dict["key3"] = link.ghostAfter
arrLinks.append(dict)
}
myDict["links"] = arrLinks as AnyObject

Related

Printing the most frequent value in a text

Let's say I have a list of string.
I saw the code on: How to count items' occurence in a List
I want to print the most frequent string as a text in my widget. How do i run this and print it in there?
Do i go by void main() ?
class user with ChangeNotifier {
static String topWord;
notifyListeners();
}
void countWord() {
var elements = ["a", "b", "c", "d", "e", "a", "b", "c", "f", "g", "h", "h", "h", "e"];
var popular = Map();
elements.forEach((element) {
if(!popular.containsKey(element)) {
popular[element] = 1;
} else {
popular[element] +=1;
}
});
print(popular);
return user.topWord = popular;
}
Attached are some screenshots when I return the results
Here you can first create the map of your counted values and then using that map you can get the maximum value of the key.
Source Here
class HomePage extends StatelessWidget {
String email;
var maxocc = maxOccurance();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("App Bar"),
),
body: Center(
child: Container(
child: Text(maxocc),
),
),
);
}
}
String maxOccurance() {
var elements = [
"a",
"b",
"c",
"d",
"e",
"a",
"b",
"c",
"f",
"g",
"h",
"h",
"h",
"e"
];
// Here creating map of all values and counting it
final folded = elements.fold({}, (acc, curr) {
acc[curr] = (acc[curr] ?? 0) + 1;
return acc;
}) as Map<dynamic, dynamic>;
print(folded);
// Here getting maximum value inside map
final sortedKeys = folded.keys.toList()
..sort((a, b) => folded[b].compareTo(folded[a]));
return "${sortedKeys.first} occurs maximun times i.e. ${folded[sortedKeys.first]}";
}
Output Here

AppSync Subscription Filters

We need a way to filter a subscription in the following manner:
type Subscription {
onPlanningViewUpdate(prop1: ["a", "b", "c"]): ReturnObject
}
ReturnObject = {prop1: "a", ...} // would pass through
ReturnObject = {prop1: "b", ...} // would pass through
ReturnObject = {prop1: "c", ...} // would pass through
ReturnObject = {prop1: "x", ...} // would NOT pass through
We have tried using the request and response mapping templates of a resolver with a NONE type data source, but the mappings seem to only get called once when the subscription is first opened. It looks like subscriptions only handle an exact match. We need a way to determine if a prop is contained in the array ["a", "b", "c"]. If prop1 == "a" or prop1 == "b" or prop1 == "c" pass through.
Here is the actual filter we want to use:
type Subscription {
onPlanningViewUpdate(site_ids: ["a", "b", "c"], planDate: "aString", lob_ids: ["x", "y", "z"]):
ReturnObject
}
ReturnObject = {site_ids: "a", planDate: "aString", lob_ids: "y"} // would pass through
ReturnObject = {site_ids: "a", planDate: "wrongString", lob_ids: "y"} // would NOT pass through
Is there a way to do this ?
Thanks,
Warren Bell

How can I convert json map to List String?

I need to get country name and country code into List as "Andorra (AD)". I can load json to a map but I cannot convert to List. How can I convert json map to List String?
"country": [
{
"countryCode": "AD",
"countryName": "Andorra",
"currencyCode": "EUR",
"isoNumeric": "020"
},
You can use the .map() function
var countryList = country.map((c) => '${c["countryName"]} (${c["countryCode"]})').toList()

'Any' is not convertible to '[[String : Any]]'

How can I cast Any type I'm getting from JSONSerialization to an array of dictionaries? My code is:
let jsonArray: [[AnyHashable: Any]]
do {
jsonArray = try JSONSerialization.jsonObject(with: jsonData, options: [.ReadingOptions.allowFragments]) as! [[AnyHashable : Any]]
}
catch {
let description = NSLocalizedString("Could not analyze earthquake data", comment: "Failed to unpack JSON")
print(description)
return
}
But compiler gives me error message:
'Any' is not convertible to '[[AnyHashable : Any]]'
P.S.
I need to parse array of dictionaries, so JSON file looks like this:
[{
"username": "admin",
"password": "123"
}, {
"username": "bbvb",
"password": "3333"
}, {
"username": "asd",
"password": "222"
}]
why are you using AnyHashable ??
Try this:
let jsonArray: Any? = nil
do {
jsonArray = try JSONSerialization.jsonObject(with: jsonData, options: []) as! [Any]
if jsonArray != nil {
if let resp = jsonArray as? [[AnyHashable : Any]]{
//your result should be here inside resp, which is an array of dictionary of key-val type `AnyHashable : Any`, although you could just use String value for the key, making your format from [[AnyHashable : Any]] to [[String : Any]]
}
}
catch {
let description = NSLocalizedString("Could not analyze earthquake data", comment: "Failed to unpack JSON")
print(description)
return
}

Using Linq to order lists within a list

I have a list of items (actually an IEnumerable). Each item has a list of values. For example:
Item1.Value[0] = "Health & Safety"
Item1.Value[1] = "Economic"
Item1.Value[2] = "Environment"
Item2.Value[0] = "Reputation"
Item2.Value[1] = "Environment"
Item2.Value[2] = "Regulatory"
...
How can I order the list of values using linq? I know I can order the list of items using something like:
Items.Orderby(x => x.something)
...but how do I get to the list of values in each item?
You can try this
Items.ForEach(i=> x.something = x.something.OrderBy(o=> o.field));
EDIT: Based off OP's comment, Value is a Dictionary<string, object>. You cannot sort a Dictionary as they are unordered by design.
Consider using a SortedDictionary<TKey, TValue>, and implement an IComparer<TKey> to fit your sorting needs:
Example:
Dictionary<string, object> values = new Dictionary<string, object>
{
{ "b", 1 }, { "a", 2 }, { "c", 3 }
};
// { { "a", 2 }, { "b", 1 }, { "c", 3 } }
SortedDictionary<string, object> keyAscending =
new SortedDictionary<string, object>(values);
public class ReverseStringComparer : IComparer<string>
{
int IComparer<string>.Compare(string x, string y)
{
return y.CompareTo(x);
}
}
// { { "c", 3 }, { "b", 1 }, { "a", 2 } }
SortedDictionary<string, object> keyDescending =
new SortedDictionary<string, object>(values, new ReverseStringComparer());