How to insert values into a nested Swift Dictionary - dictionary

I'm trying to insert new key-value pair in dictionary, which nested in another one Dictionary:
var dict = Dictionary<Int, Dictionary<Int, String>>()
dict.updateValue([1 : "one", 2: "two"], forKey: 1)
dict[1]?[1] // {Some "one"}
if var insideDic = dict[1] {
// it is a copy, so I can't insert pair this way:
insideDic[3] = "three"
}
dict // still [1: [1: "one", 2: "two"]]
dict[1]?[3] = "three" // Cannot assign to the result of this expression
dict[1]?.updateValue("three", forKey: 3) // Could not find a member "updateValue"
I believe should be a simple way to handle it, but I spent an hour and still can't figure it out.
I can use NSDictionary instead, but I really like to understand how I should manage nested Dictionaries in Swift?

Dictionarys are value types so are copied on assignment. As a result you are going to have to get the inner dictionary (which will be a copy), add the new key, then re-assign.
// get the nested dictionary (which will be a copy)
var inner:Dictionary<Int, String> = dict[1]!
// add the new value
inner[3] = "three"
// update the outer dictionary
dict[1] = inner
println(dict) // [1: [1: one, 2: two, 3: three]]
You could use one of the new utility libraries such as ExSwift to make this a bit simpler:
dict[1] = dict[1]!.union([3:"three"])
This uses the union method that combines two dictionaries.

Related

java8 stream style for retrieving a inner part of map through a field list?

For example, given a map like below:
{
"k1": {
"k2": {
"k3": {
"k4": "v"
}
}
}
}
and a field list ["k1","k2","k3"], I need to retrieve the part {"k4": "v"}.
Below is my java7-style code:
// Ignore the map building code.
Map map1 = new HashMap();
Map map2 = new HashMap();
Map map3 = new HashMap();
Map map4 = new HashMap();
map4.put("k4", "v");
map3.put("k3", map4);
map2.put("k2", map3);
map1.put("k1", map2);
Map map = map1;
System.out.println(map); //=> {k1={k2={k3={k4=v}}}}
// Code to be transformed to java8 style
List<String> fields = Arrays.asList("k1", "k2", "k3");
for(String field: fields) {
map = (Map) map.get(field);
}
System.out.println(map); //=> {k4=v}
Then how to transform above code to java 8 stream style?
I don’t think that there is any benefit in converting this into a functional style; the loop is fine and precisely expresses what you are doing.
But for completeness, you can do it the following way:
map = (Map)fields.stream()
.<Function>map(key -> m -> ((Map)m).get(key))
.reduce(Function.identity(), Function::andThen).apply(map);
This converts each key to a function capable of doing a map lookup of that key, then composes them to a single function that is applied to you map. Postponing the operation to that point is necessary as functions are not allowed to modify local variables.
It’s also possible to fuse the map operation with the reduce operation, which allows to omit the explicit type (<Function>):
map = (Map)fields.parallelStream()
.reduce(Function.identity(), (f, key)->f.andThen(m->((Map)m).get(key)), Function::andThen)
.apply(map);
Maybe you recognize now, that this is a task for which a simple for loop is better suited.
How about?
fields.stream().reduce(map1, (m, key) -> (Map) m.get(key), (a, b) -> a);

Swift Remove element from an array and then remove the same element from an array inside of a dictionary

So I have a struct and a dictionary that look like this:
struct minStruct {
var labelText:String?
var descText:String?
var imaginator:UIImage?
var rea:String?
var url:NSURL?}
var dict = [String:[minStruct]]()
Thus, I have a dictionary with the value as an array of structs. In my application I create an array of all the structs inside the dictionary to be able to show the structs in a tableView, which is done by this code:
let dictValues = Array(dict.values)
let dictFlat = Array(dictValues.flatten())
The new array dictFlat is used for populating the tableView, as it contains every struct that was contained inside of the original dictionary. If I would like to remove a struct from the tableView, i would of course remove it from the array dictFlat, however I need to remove the same struct from the original dictionary (dict) to achieve what I want. So my question is simply how to remove the same struct that is deleted from the array dictFlat from the dictionary dict. To clarify, you could you this example:
dict = ["Food":[minStruct(labelText: "this is a string", descText: "Also a string", imaginator: UIImage(named: "image-name")!, rea: "also a string", url: NSURL(string: "https://www.google.com")]]
Now dictFlat will contain the struct displayed inside of dict above, and now I want to delete that struct from both. Using swipe to delete from the tableView, the only struct that will be deleted is the one inside of dictFlat (using the indexPath to delete just as you would usually do when deleting from a tableView). Now I want to delete the same item which was deleted from dictFlat and also from the tableView, from the original dictionary (dict). So what I want is to check if dict contains the struct that was deleted from dictFlat, and if it does contain it, it shall be deleted.
I hope that I was clear enough, thanks in advance!
What is the trouble? See the example, I used there [Int] as a value, but it could be anything else
var dict:[String:[Int]] = [:]
let arr0 = [1,2,3,4,5]
let arr1 = [2,3,4,5,6]
dict["arr0"] = arr0
dict["arr1"] = arr1
// working copy
var arr = dict["arr0"] ?? []
// remove one value
arr.removeAtIndex(2)
// update your dictionary
dict["arr0"] = arr
print(dict) // ["arr1": [2, 3, 4, 5, 6], "arr0": [1, 2, 4, 5]]

swift - create empty string : tuple dictionary using literal

can anyone explain why line 1 works to create an empty swift dictionary but line 2 doesn't when i try to create a swift dictionary with int key and tuple of double values .... how should it be done?
var testDic2 = [Int:Double]()
var testDic3 = [Int:(Double,Double)]()
I've tried various combinations in playgrounds and the only version where it doesnt give me a compiler error is as follows
var possibleTips = [Int(): (tipAmt:Double(), total:Double())]
but im not sure this last form is declaring the dictionary as i intend it (ie as per testDict3 above)
The compiler isn't sure how to instantiate the type in your second and third example. Instead, you can declare the type and use an empty dictionary initializer:
var testDic:[Int:(Double,Double)] = [:]

Can I insert into a map by key in F#?

I'm messing around a bit with F# and I'm not quite sure if I'm doing this correctly. In C# this could be done with an IDictionary or something similar.
type School() =
member val Roster = Map.empty with get, set
member this.add(grade: int, studentName: string) =
match this.Roster.ContainsKey(grade) with
| true -> // Can I do something like this.Roster.[grade].Insert([studentName])?
| false -> this.Roster <- this.Roster.Add(grade, [studentName])
Is there a way to insert into the map if it contains a specified key or am I just using the wrong collection in this case?
The F# Map type is a mapping from keys to values just like ordinary .NET Dictionary, except that it is immutable.
If I understand your aim correctly, you're trying to keep a list of students for each grade. The type in that case is a map from integers to lists of names, i.e. Map<int, string list>.
The Add operation on the map actually either adds or replaces an element, so I think that's the operation you want in the false case. In the true case, you need to get the current list, append the new student and then replace the existing record. One way to do this is to write something like:
type School() =
member val Roster = Map.empty with get, set
member this.Add(grade: int, studentName: string) =
// Try to get the current list of students for a given 'grade'
let studentsOpt = this.Roster.TryFind(grade)
// If the result was 'None', then use empty list as the default
let students = defaultArg studentsOpt []
// Create a new list with the new student at the front
let newStudents = studentName::students
// Create & save map with new/replaced mapping for 'grade'
this.Roster <- this.Roster.Add(grade, newStudents)
This is not thread-safe (because calling Add concurrently might not update the map properly). However, you can access school.Roster at any time, iterate over it (or share references to it) safely, because it is an immutable structure. However, if you do not care about that, then using standard Dictionary would be perfectly fine too - depends on your actual use case.

Upcasting F# record created through reflection

I've been messing about with F# and it's Reflection, trying to create a Record type object dynamically from within F#, I got most of it working (as you can see below) but one thing - the record I create through reflection has type "obj" instead the one it should ("Person") and I can't seem to be able to upcast it in any way.
#light
type Person = {
Name:string;
Age:int;
}
let example = {Name = "Fredrik"; Age = 23;}
// example has type Person = {Name = "Fredrik"; Age = 23;}
let creator = Reflection.FSharpValue.PrecomputeRecordConstructor(example.GetType(),
System.Reflection.BindingFlags.Public)
let reflected = creator [| ("thr" :> obj); (23 :> obj) |]
// here reflected will have the type obj = {Name = "thr"; Age = 23;}
// Function that changes the name of a Person record
let changeName (x:Person) (name:string) =
{ x with Name = name }
// Works with "example" which is has type "Person"
changeName example "Johan"
// But not with "reflected" since it has type "obj"
changeName reflected "Jack" // Error "This expression has type obj but is here used with type Person. "
// But casting reflected to Person doesn't work either
(reflected :> Person) // Type constraint mismatch. The type obj is not compatible with
// type Person. The type 'obj' is not compatible with the type 'Person'.
// C:\Users\thr\Documents\Visual Studio 2008\Projects\
// Reflection\Reflection\Script.fsx 34 2 Reflection
Try using the other cast operator (as you're casting the other way this time)
So changeName (reflected :?> Person) "Jack"

Resources