How to Mutate an Array in a Dictionary

How to Mutate an Array in a Dictionary?

In swift, structures are copied by value when they get assigned to a new variable. So, when you assign a1 to the value in the dictionary it actually creates a copy. Here's the line I'm talking about:

var a1 = d1["a"]!

Once that line gets called, there are actually two lists: the list referred to by d1["a"] and the list referred to by a1. So, only the second list gets modified when you call the following line:

a1.append("s1")

When you do a print, you're printing the first list (stored as the key "a" in dictionary d1). Here are two solutions that you could use to get the expected result.

Option1: Append directly to the array inside d1.

var d1 = [String : [String]]()
d1["a"] = [String]()
d1["a"]?.append("s1")
println(d1)

Option 2: Append to a copied array and assign that value to "a" in d1.

var d1 = [String : [String]]()
d1["a"] = [String]()
var a1 = d1["a"]!
a1.append("s1")
d1["a"] = a1
println(d1)

The first solution is more performant, since it doesn't create a temporary copy of the list.

Iterate and mutate an Array of Dictionaries Swift 3

You are trying to iterate through an array treating it like a dictionary.
You'll have to iterate through the array and then through your key/value pairs

for dictionary in arrayOfMutatingDictionaries{
for (key,value) in dictionary{
//Do your stuff
}
}

Adding a key/value pair is pretty straightforward.

for i in 0..< arrayOfMutatingDictionaries.count{
arrayOfMutatingDictionaries[i][yourkey] = yourvalue
}

You can also increment the existing values like this

for i in 0..<arrayOfMutatingDictionaries.count{
for (key,value) in arrayOfMutatingDictionaries[i]{
arrayOfMutatingDictionaries[i][key] = value+1
}
}

Preferred way of mutating dictionary inside function/method and returning to the caller?

I'd say better to not return

Well look no further than list.sort()

It sorts list in-place, meaning original list changes, and nothing is returned.

The reason for returning None is so users do not get confused (thinking original list is preserved)

The most important thing is to properly name what you're doing

e.g.

def fill_with_defaults(cfg):
...

And then fill_with_defaults(configuration) is looking perfectly readable

And as for "explicit", no return value is even better because the reader knows something is changed in-place

meaning he wouldn't consider config2 = fill_with_defaults(configuration)

leading to buggy code (cuz changing one config affects other)

swift dictionary nested array manipulation - cannot mutate nested array inside dictionary

Good question yes it creates the copy of the value in your case the value is Array

    var alphaList = dict["alpha"] 
/* which is the copy of original array
changing it will change the local array alphaList as you can see by your output */
output : {Some "b"}

In order to get the original array directly use

dict["alpha"]?.removeAtIndex(1)

Or update it using the key

alphaList?.removeAtIndex(1)
dict["alpha"] = alphaList

Apple : Assignment and Copy Behavior for Strings, Arrays, and Dictionaries

Swift’s String, Array, and Dictionary types are implemented as structures. This means that strings, arrays, and dictionaries are copied when they are assigned to a new constant or variable, or when they are passed to a function or method.

This behavior is different from NSString, NSArray, and NSDictionary in Foundation, which are implemented as classes, not structures. NSString, NSArray, and NSDictionary instances are always assigned and passed around as a reference to an existing instance, rather than as a copy. "

How to use a mutable array as dictionary value in a performant way?

Note that both Swift array and NSMutableArray under the hood kinda do the same things: when they have no more allocated space for new items, they allocate a new buffer. And the new buffer allocation logic should be fairly similar in both Swift and Objective-C.

The problem with your Swift array code, as Alexander pointed out in his comment, is the fact that you create a local copy of the array that is stored into the dictionary. And as soon as you mutate that local array, the copy-on-write mechanism triggers a copy of the array buffer, which results into another heap allocation. And the bigger the array, the more it takes to duplicate the buffer.

The nonlinear growth you see is due to the fact that the array buffer increases don't occur that often, as the array implementations have a pretty good heuristic for the capacity increase, in order to avoid allocations every time a new element is added. However the buffer duplication due to copy-on-write happens at every iteration.

You will get better results with the Swift arrays if you mutate them in place:

for i in 0..<1_000_000 {
let key = i % 7
dict[key, default: [Int]()].append(i)
}

Both measurements and Instruments show a dramatically improved performance with the above change, with the Swift code being faster than the Objective-C one.

Mutate Nested Dictionary With Paths

The best way to do this dynamically is to keep on using NSMutableDictionary in Swift. It does not appear there is a good way to do this with Swift dictionaries, besides creating structs/classes to represent the actual keys, instead of doing it dynamically. Thanks matt and Sulthan.

How to change value of an element in dictionary of arrays?

If you know the index of the number you would like to change out of the three, you can change the number 3 directly using the subscripts ["xx"]?["x1"]?[2].

var myArray = [
"xx": [
"x1": [1, 2, 3],
"x2": [4, 5, 6],
"x3": [7, 8, 9]
],
"yy": [
"y1": [10, 11, 12],
"y2": [13, 14, 15],
"y3": [16, 17, 18]
]
]

array["xx"]?["x1"]?[2] = 4

How to add array of dictionary via logstash filter mutate from csv?

The square brackets in Logstash Filters do not behave like array elements/entries as in other programming languages, e.g. Java.

[Applicant][0][Applicant_Income]

is not the right syntax to set the value of field Applicant_Income of the first element (zero-based index) in the Applicant-Array. Instead, you create sub-elements 0, 1, 2 underneath the Applicant-element as shown in Figure 1.

To create an array of objects, you should use the ruby filter plugin (https://www.elastic.co/guide/en/logstash/current/plugins-filters-ruby.html). Since you can execute arbitrary ruby code with that filter, it gives you more control/freedom:

filter {
csv {
separator => ","
skip_header => true
columns => [LoanID,Applicant_Income1,Occupation1,Time_At_Work1,Date_Of_Join1,Gender,LoanAmount,Marital_Status,Dependents,Education,Self_Employed,Applicant_Income2,Occupation2,Time_At_Work2,Date_Of_Join2,Applicant_Income3,Occupation3,Time_At_Work3,Date_Of_Join3]
}

mutate {
convert => {
"Applicant_Income1" => "float"
"Time_At_Work1" => "float"
"LoanAmount" => "float"
"Applicant_Income2" => "float"
"Time_At_Work2" => "float"
"Applicant_Income3" => "float"
"Time_At_Work3" => "float"
}
}

ruby{
code => '
event.set("Applicant",
[
{
"Applicant_Income" => event.get("Applicant_Income1"),
"Occupation" => event.get("Occupation1"),
"Time_At_Work" => event.get("Time_At_Work1"),
"Date_Of_Join" => event.get("Date_Of_Join1")
},
{
# next object...
}
]
'
}

date {
match => [ "Date_Of_Join1", "yyyy-MM-dd'T'HH:mm:ss.SSZZ" ]
}

date {
match => [ "Date_Of_Join2", "yyyy-MM-dd'T'HH:mm:ss.SSZZ" ]
}

date {
match => [ "Date_Of_Join3", "yyyy-MM-dd'T'HH:mm:ss.SSZZ" ]
}

mutate{
remove_field => [
"Applicant_Income1",
"Occupation1",
"Time_At_Work1",
"Date_Of_Join1",
"Applicant_Income2",
"Occupation2",
"Time_At_Work2",
"Date_Of_Join2",
"Applicant_Income3",
"Occupation3",
"Time_At_Work3",
"Date_Of_Join3"
]
}
}

With event.set you add a field to the document. The first argument is the fieldname, the second one its value. In this case, you add the field "Applicants" to the document with an array of objects as its value.

event.get is used to get the value of a certain field in the document. You retrieve the value by passing the fieldname to the method.

Please refer to this guide
https://www.elastic.co/guide/en/logstash/current/event-api.html to get more insights of the event API.

I hope I could help you.

Mutate a list within a dictionary

I think I came up with something like what you want. One problem I ran into was how you formatted your dictionary. In your original post, you had double lists for all dictionary values. I think it would be easier to format the dictionary like I did. One change I made to keep in mind is that in the changeQuantity() function, I switched the inventory number from a string to an int value. I'm not sure how you want to it be, but the format can easily be changed by making the newquant arg a string type. Hope this helped!

bookdict = {'Dickens,Charles': ['Hard Times', '7', '27.00'],
'Shakespeare,William': [['Rome And Juliet', '5', '5.99'], ['Macbeth', '3', '7.99']]}

def changeQuantity(authorlast,authorfirst,bookname,newquant):
bookfound = False
author = str(authorlast)+','+str(authorfirst)
if not author in bookdict:
return "Author not in inventory"
temp = bookdict.values()
if type(bookdict[author][0]) == list:
for entry in bookdict[author]:
if entry[0] == bookname:
entry[1] = newquant
bookfound = True
else:
if bookdict[author][0] == bookname:
bookdict[author][1] = newquant
bookfound = True
if bookfound == False:
return "Book not in author inventory"
return bookdict

def sumInventory():
sum = 0
for key in bookdict.keys():
if type(bookdict[key][0]) == list:
for entry in bookdict[key]:
sum += int(entry[1])
else:
sum += int(bookdict[key][1])
return sum

print changeQuantity("Dickens","Charles","Hard Times",2)
print changeQuantity("a","b","Hard Times",2)
print changeQuantity("Shakespeare", "William", "a", 7)
print sumInventory()

Output:

{'Shakespeare,William': [['Rome And Juliet', '5', '5.99'], ['Macbeth', '3', '7.99']], 'Dickens,Charles': ['Hard Times', 2, '27.00']}
Author not in inventory
Book not in author inventory
10


Related Topics



Leave a reply



Submit