Unpacking a Dictionary from within an ArraySlice - swift

I have an ArraySlice<Dictionary<String, String>> containing only one dictionary inside. This looks like the following:
[["high": "4", "investpercent": "6.0", "objective": "2.0", "savings": "2.0", "expenses": "1.0", "date": "2017-09-26", "low": "2"]]
However I wanted to manipulate the dictionary with subscripts, which is not implemented in ArraySlice. In typical slices one would, as per found question in SO, do something like:
let dictionary = ["a": 1, "b": 2, "c": 3]
var smallerDictionary: [String: Int] = [:]
for (key, value) in dictionary.dropFirst() {
smallerDictionary[key] = value
}
print(smallerDictionary) // ["a": 1, "c": 3]
Which I tried and does not work in ArraySlice.
How do I "unpack" a dictionary from within an ArraySlice?

If your ArraySlice is called slice, use slice.first! or slice[slice.startIndex] to access the contained dictionary:
let slice: ArraySlice<[String:String]> = [["high": "4", "investpercent": "6.0", "objective": "2.0", "savings": "2.0", "expenses": "1.0", "date": "2017-09-26", "low": "2"]]
var smallerDictionary: [String: String] = [:]
for (key, value) in slice.first!.dropFirst() {
smallerDictionary[key] = value
}
print(smallerDictionary)
Note: Calling dropFirst() on a dictionary will give you unpredictable results because dictionaries are unordered.
It should go without saying that you should make sure your ArraySlice isn't empty before attempting to access the contained dictionary. You can do that by explicitly checking slice.count > 0, !slice.isEmpty, or properly unwrapping slice.first.

Related

Access a JSONB array of objects as an object of arrays

I have a JSONB column in my Postgres 9.6 database with roughly the following structure
[
{
"A": "some value",
"B": "another value",
"foo": "bar",
"x": "y"
},
{
"B": "abc",
"C": "asdf"
}
]
It is always an array of objects, the number of array elements varies. Some of the object keys are in each array element, but not all of them. The real objects have many more keys, a few hundred are common.
In certain situations, I need to get the value of a specific key for each array element. For example, if I want to access the key "B" the result should be
["another value", "abc"]
if I access "foo" the result should be
["bar", null]
Is there a reasonably efficient way to fetch all values for a specific key in a SQL query? It should work independent of the number of objects in the array, and ideally it should not get slower if the number of key in the objects get much larger.
You can use the jsonb_array_elements to extract each object, aggregate those you want in an array using ARRAY_AGG and then convert that into a json array using array_to_json:
WITH j(json) AS (
VALUES ('[
{
"A": "some value",
"B": "another value",
"foo": "bar",
"x": "y"
},
{
"B": "abc",
"C": "asdf"
}
]'::jsonb)
)
SELECT array_to_json(ARRAY_AGG(elem->'B'))
FROM j, jsonb_array_elements(json) elem
;
array_to_json
-------------------------
["another value","abc"]
(1 row)
WITH j(json) AS (
VALUES ('[
{
"A": "some value",
"B": "another value",
"foo": "bar",
"x": "y"
},
{
"B": "abc",
"C": "asdf"
}
]'::jsonb)
)
SELECT array_to_json(ARRAY_AGG(elem->'foo'))
FROM j, jsonb_array_elements(json) elem
;
array_to_json
---------------
["bar",null]
(1 row)

How can I append to a specific dictionary within an array of dictionaries in swift?

My data structure:
var defs = [["a":"b","c":"d"],["e":"f","g":"h"]]
I have tried the following:
dict[1]["testKey"] = "testValue"
in an attempt to attain the following:
defs = [["a":"b","c":"d"],["e":"f","g":"h","testKey":"testValue"]]
This doesn't work though. Does anyone have a good solution?
You have a typo in your code (I see you're using dict instead of defs but this works fine:
var defs = [
[
"a": "b",
"c": "d"
],
[
"e": "f",
"g": "h"
]
]
defs[1]["key"] = "value"
print(defs[1]["key"]) // "Optional("value")\n"
var defs = [["a":"b","c":"d"],["e":"f","g":"h"]]
defs[1]["testKey"] = "testValue"
print(defs)
prints:
[["a": "b", "c": "d"], ["e": "f", "testKey": "testValue", "g": "h"]]
The elements contained within the defs array are of type Dictionary, which by definition is unordered. If the order is an issue, you have to use another collection type.

Concatenate dictionary values in Swift

I created a dictionary in Swift like:
var dict:[String : Int] = ["A": 1, "B": 2, "C": 3, "D": 4]
print(dict["A"]!)
The computer prints number 1, but how do I concatenate these values such that the output is 1234 instead of a single integer?
The key-value pairs in a Dictionary are unordered. If you want to access them in a certain order, you must sort the keys yourself:
let dict = ["A": 1, "B": 2,"C": 3,"D": 4]
let str = dict.keys
.sorted(by: <)
.map { dict[$0]! }
.reduce ("") { $0 + String($1) }
Or alternatively:
let str = dict.keys
.sorted(by: <)
.map { String(dict[$0]!) }
.joined()
No idea about the relative performance of the two as I haven't benchmarked them. But unless your dictionary is huge, the difference will be minimal.
let dict = ["A": 1, "B": 2, "C": 3, "D": 4]
for entry in dict.sorted()
{
print("\(entry.1)", terminator: "")
}

Add new entries to a "complex" dictionary

I have a more "complex" dictionary that I am trying to add new entries to. The dictionary code is as follows:
var users: [[String:Any]] = [
[
"firstName": "Bill",
"lastName": "G"
]
]
I tried adding a new entry with this code:
users[1]["firstName"] = "Steve"
users[1]["lastName"] = "J"
print(users) // fatal error: Array index out of range
But receive "fatal error: Array index out of range" I looked at several examples but all seem to deal with simpler dictionaries. What am I missing?
You need to first create an instance of the dictionary and add it to the array, you can then add key:value pairs to it:
var users: [[String:Any]] = [
[
"firstName": "Bill",
"lastName": "G"
]
]
users.append([String:Any]())
users[1]["firstName"] = "Steve"
users[1]["lastName"] = "J"
print(users) // [["firstName": "Bill", "lastName": "G"], ["firstName": "Steve", "lastName": "J"]]
You can even do it in a single statement like this:
users.append(["firstName": "Steve", "lastName": "J"])
If you don't append a new element on to the array then when you try to reference the next index it will be out of range.
This works in a playground
var users: [[String:Any]] = [
[
"firstName": "Bill",
"lastName": "G"
]
]
users[0]["firstName"] = "Steve"
users[0]["lastName"] = "J"
users
Using index 0, not 1 like you were using which causes the index out of bounds error
Or the more dynamic approach
var users = [[String:AnyObject]]()
let personA = ["Steve":"J"]
let personB = ["Foo":"Z"]
users.append(personA)
users.append(personB)
users

Swift Dictionary Multiple Key Value Pairs - Iteration

In Swift I want to make an array of dictionaries (with multiple key value pairs) and then iterate over each element
Below is the expected output of a possible dictionary. Not sure how to declare and intitialize it (somewhat similar to array of hashes in Ruby)
dictionary = [{id: 1, name: "Apple", category: "Fruit"}, {id: 2, name: "Bee", category: "Insect"}]
I know how to make an array of dictionary with one key value pair.
For example:
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
to declare an array of dictionary, use this:
var arrayOfDictionary: [[String : AnyObject]] = [["id" :1, "name": "Apple", "category" : "Fruit"],["id" :2, "name": "Microsoft", "category" : "Juice"]]
I see that in your dictionary, you mix number with string, so it's better use AnyObject instead of String for data type in dictionary.
If after this code, you do not have to modify the content of this array, declare it as 'let', otherwise, use 'var'
Update: to initialize within a loop:
//create empty array
var emptyArrayOfDictionary = [[String : AnyObject]]()
for x in 2...3 { //... mean the loop includes last value => x = 2,3
//add new dictionary for each loop
emptyArrayOfDictionary.append(["number" : x , "square" : x*x ])
}
//your new array must contain: [["number": 2, "square": 4], ["number": 3, "square": 9]]
let dic_1: [String: Int] = ["one": 1, "two": 2]
let dic_2: [String: Int] = ["a": 1, "b": 2]
let list_1 = [dic_1, dic_2]
// or in one step:
let list_2: [[String: Int]] = [["one": 1, "two": 2], ["a": 1, "b": 2]]
for d in list_1 { // or list_2
print(d)
}
which results in
["one": 1, "two": 2]
["b": 2, "a": 1]
let airports: [[String: String]] = [["YYZ": "Toronto Pearson", "DUB": "Dublin"]]
for airport in airports {
print(airport["YYZ"])
}