Reorder dictionary keys

I have dictionary in below format and would like to check if we have any existing methos that can reorder dictionary if we provide the array with the key names in desired order?

I would like to see my final dictionary in below order of key along with their values.

desired_order = [“date”, “time”, “field2”, “field1”, “field3”, “field4”, “field5”, “field6”, “field7”]

[Dict{String, Any}("field1" => 26, "field2" => 1, "time" => "14:00", "field3" => 0, "date" => "2024-03-09", "field4" => 102, "field5" => 17, "field6" => 10, "field7" => 97), Dict{String, Any}("field1" => 1, "field2" => 1, "time" => "04:00", "field3" => 0, "date" => "2024-03-09", "field4" => 6, "field5" => 0, "field6" => 2, "field7" => 5), Dict{String, Any}("field1" => 18, "field2" => 1, "time" => "17:45", "field3" => 7, "date" => "2024-03-07", "field4" => 101, "field5" => 9, "field6" => 10, "field7" => 114), Dict{String, Any}("field1" => 0, "field2" => 0, "time" => "06:00", "field3" => 0, "date" => "2024-03-10", "field4" => 26, "field5" => 5, "field6" => 5, "field7" => 46)]
1 Like

Dictionaries are inherently unordered. If you want to order the contents you’ll need to convert it into a different form, the most obvious is a vector of pairs.

pair_vec = [dict...]

This vector can then be sorted. To sort in the order we want we can say that for two pairs, x and y, x comes first if its key is before y’s key in desired_order. We put this in a function:

islessthan(x, y) = findfirst((==)(first(x)), desired_order) <= findfirst((==)(first(y)), desired_order)

Note here x, y are pairs, so first(x) is equivalent to the key of x.

(==)(val) is the same as s -> s == val. That is, it’s a function that returns true if its argument is the same as val.

Lastly, findfirst(fn, desired_order) returns the index of the first element of desired_order where fn is true. In our example, it’s the index of the element of desired_order that equals the key of x.

Then to sort in our desired order use:

sort(pair_vec; lt=islessthan)
1 Like

For ordered dictionaries, there’s OrderedDict, this will provide exactly what you want.

1 Like

There are also an OrderedDict data structure which would do the job:

using DataStructures

desired_order = ["date", "time", "field2", "field1", "field3", "field4", "field5", "field6", "field7"]

data = [Dict{String, Any}("field1" => 26, "field2" => 1, "time" => "14:00", "field3" => 0, "date" => "2024-03-09", "field4" => 102, "field5" => 17, "field6" => 10, "field7" => 97), Dict{String, Any}("field1" => 1, "field2" => 1, "time" => "04:00", "field3" => 0, "date" => "2024-03-09", "field4" => 6, "field5" => 0, "field6" => 2, "field7" => 5), Dict{String, Any}("field1" => 18, "field2" => 1, "time" => "17:45", "field3" => 7, "date" => "2024-03-07", "field4" => 101, "field5" => 9, "field6" => 10, "field7" => 114), Dict{String, Any}("field1" => 0, "field2" => 0, "time" => "06:00", "field3" => 0, "date" => "2024-03-10", "field4" => 26, "field5" => 5, "field6" => 5, "field7" => 46)]

od_data = [OrderedDict(k=>d[k] for k in desired_order) for d in data]

Now od_data containts the rightly ordered Dicts:

julia> od_data[1]
OrderedDict{String, Any} with 9 entries:
  "date"   => "2024-03-09"
  "time"   => "14:00"
  "field2" => 1
  "field1" => 26
  "field3" => 0
  "field4" => 102
  "field5" => 17
  "field6" => 10
  "field7" => 97
3 Likes

@Dan This works perfect but I have one more issue here, the data may not have all the keys that specified in the desired_order array, so can we implement haskey logic within your solution above?

@Dan Nvm, I was able to write the logic. Thanks!

@Dan I am adding one more pair of values to this dict say od_data[“work_data”] and assigning the values using same logic above and the order is getting shuffled if I do this, Any thoughts? may be we need to create separate dict and merge both instead of directly assigning.?

The order of the keys is the same as the insertion order (unless the keys are reordered). Therefore, to get key a before key b, a needs to be inserted first. I suppose that dummy entries can be inserted as placeholders for future values if the key order requires it. When updating the value of a key, it does not move in the order.

It is worth mentioning Dictionaries.jl as well, which provides an alternative implementation of dictionaries which are ordered by default.

3 Likes