I have a dictionary in Julia that I want to sort by values. I found a couple of ways to do it. For instance
dict = Dict(i => sqrt(i*rand()) for i = 1:20)
dict= sort(dict;byvalue = true) # method 1
dict = OrderedDict(i => sqrt(i*rand()) for i = 1:20) #method 2 using ordereddict package [https://github.com/JuliaCollections/DataStructures.j][1]
# I don't want to use collect() method as I do not want the tuples of dictionary.
However, sometimes these two methods do lose their orders down the line when they are passed from functions to functions. Are there any other methods where the ordered dictionary is immutable in Julia?
As by the docs, for OrderedDict
order refers to insertion order.
I don't know how this can "lose its order down the line", but maybe you are just mutating stuff?
Probably what you want is closer to a SortedDict; however, this sorts by keys, not values. A dictionary sorted by values is a bit of an unusual application.
If you want a mutable data structure with fast lookup by key and iteration sorted by value, you could emulate this by a two-level approach: a normal dict for storing a mapping between original keys and tokens, and a second SortedMultiDict{ValueType, Nothing} to emulate a sorted multiset into which the tokens index. Then you define your own mechanism for indirect lookup through tokens somehow like this:
function insert!(d::ValueSortedDict, k, v)
_, token = insert!(d.values, v, nothing)
d.keys[k] = token
end
getindex(d::ValueSortedDict, k) = deref_key((d.values, d.keys[k]))
And accordingly for other get/set style functions. (I didn't test this, it's just read off the docs.)
OTOH, if you never intend to mutate things, you can just do a very similar thing where you store a Dict{KeyType, Int} and a Vector{ValueType} together and sort! the vector once at the beginning. (Dictionaries.jl, described in #mcabbot's answer, is basically implementing this.)
You might be interested in Dictionaries.jl:
julia> dict = Dict(i => (i/10 + rand(1:99)) for i = 1:7)
Dict{Int64, Float64} with 7 entries:
5 => 16.5
4 => 23.4
6 => 98.6
7 => 56.7
2 => 7.2
3 => 58.3
1 => 85.1
julia> using Dictionaries
julia> sort(Dictionary(dict))
7-element Dictionary{Int64, Float64}
2 │ 7.2
5 │ 16.5
4 │ 23.4
7 │ 56.7
3 │ 58.3
1 │ 85.1
6 │ 98.6
julia> map(sqrt, ans)
7-element Dictionary{Int64, Float64}
2 │ 2.6832815729997477
5 │ 4.06201920231798
4 │ 4.8373546489791295
7 │ 7.52994023880668
3 │ 7.635443667528429
1 │ 9.22496612459905
6 │ 9.929753269845127
Related
SELECT MACStringToOUI('aa:bb:cc:dd:ee:ff')
gives me 11189196 which are the first three octets as a UInt64 number.
I'd like to convert it back to MacAddress so the desired result is aa:bb:cc:00:00:00.
I believe there's no native function for that. Do I have to move bits manually?
*256^3
SELECT MACNumToString(MACStringToOUI('aa:bb:cc:dd:ee:ff')*256*256*256) r;
Query id: 3a3637c3-d068-4b00-9024-01129517c3e2
┌─r─────────────────┐
│ AA:BB:CC:00:00:00 │
└───────────────────┘
I think I've heard that there is data structure something like tree to store dictionary entries.
It may look like:
c ┬ a ┬ b
│ ├ r
│ ├ s ─ e
│ └ t
├ i ─ ...
:
Is there any name for this data structure?
I cannot find it...
Thanks for your help, thank you in advance!
A trie might be what you're looking for.
A trie, also called digital tree and sometimes radix tree or prefix tree ..., is a kind of search tree - an ordered tree data structure that is used to store a dynamic set or associative array where the keys are usually strings. ... [A node's] position in the tree defines the key with which it is associated. All the descendants of a node have a common prefix of the string associated with that node...
A trie for keys "A","to", "tea", "ted", "ten", "i", "in", and "inn".
Given a dictionary:
> d = Dict{Int, Int}(1=>123, 2=>51, 4=>23)
Dict{Int64,Int64} with 3 entries:
4 => 23
2 => 51
1 => 123
I could access a dictionary's value by its key, e.g.:
> d[4]
23
Or I could looped through the key-value pairs as such:
> for i in d
println(i)
end
4=>23
2=>51
1=>123
I've tried accessing the key as the first element of the list or even i.key, but it doesn't seem to be the right syntax:
julia> for i in d
println(i.key)
end
ERROR: type Pair has no field key
in macro expansion; at ./REPL[22]:2 [inlined]
in anonymous at ./<missing>:?
julia> for i in d
println(i[0])
end
ERROR: BoundsError: attempt to access 4=>23
at index [0]
in getindex(::Pair{Int64,Int64}, ::Int64) at ./operators.jl:609
in macro expansion; at ./REPL[23]:2 [inlined]
in anonymous at ./<missing>:?
And then I remembered that Julia is not 0th index, so it should be:
> for i in d
println(i[1], ' ', i[2])
end
4 23
2 51
1 123
> for i in d
println(i[1], ' ', i[2])
end
4 23
2 51
1 123
In this case is the BoundsError somewhat like the Python's IndexError when an index of the list isn't found?
The other part of the question is on SortedDict, how do I access the last Nth element in the SortedDict?
I've tried using the index syntax and I retrieved the value but not the tuple of (key,value).
julia> import DataStructures: SortedDict
julia> sd = SortedDict(d)
DataStructures.SortedDict{Int64,Int64,Base.Order.ForwardOrdering} with 3 entries:
1 => 123
2 => 51
4 => 23
julia> sd[end]
23
Also, how can I sort the dictionary based on the value?
And, lastly, how to reverse the sorted dict?
I've tried using Base.Order.ReverseOrding but it threw a MethodError:
julia> sd = SortedDict{Base.Order.ReverseOrdering}(d)
ERROR: MethodError: Cannot `convert` an object of type Dict{Int64,Int64} to an object of type DataStructures.SortedDict{Base.Order.ReverseOrdering,D,Ord<:Base.Order.Ordering}
This may have arisen from a call to the constructor DataStructures.SortedDict{Base.Order.ReverseOrdering,D,Ord<:Base.Order.Ordering}(...),
since type constructors fall back to convert methods.
in DataStructures.SortedDict{Base.Order.ReverseOrdering,D,Ord<:Base.Order.Ordering}(::Dict{Int64,Int64}) at ./sysimg.jl:53
I am not a Python user, but the documentation for IndexError looks similar to the documentation for BoundsError. Note that you can always query current Julia documentation with ?, e.g.
?BoundsError
You can sort dictionary keys and values:
d = Dict{Int,Int}(1 => 2, 3 => 4)
k = sort(collect(keys(d)) ### collect() forms an array that you can sort
v = sort(collect(values(d))
but I cannot see why you would want to sort by value. Why not simply use the values as keys?
You can loop through keys or values easily:
for k in keys(d) ### or "for v in values(d)..."
println(k)
end
When using SortedDict, make sure that such an ordering makes sense. In this toy example the keys of d are integers, and they have a logical order with isless and isequal; see documentation here.
You can obtain the last entry of a SortedDict with last:
using DataStructures
D = SortedDict(d)
last(D) ### 3=>4
Use the Reverse module to flip the order:
using Reverse
D2 = SortedDict(d, Reverse)
I have a dict filled with Job types
A job has a name(string) and a score(int)
I managed to load the jobs into a Dict, and I want to sort them using the Sort method based on the jobs scores. However, when I sort the dict (call it jobs), it gives me a new vector of the sorted scores.
is there any way to sort the dict while preserving which job has its specific score?
jobs = Dict([(nurse, nurse.score), (construction, construction.score),
(programmer, programmer.score), (retail, retail.score)])
sort(collect(values(jobs)))
so if I have nurse with a score of 3, programmer with a score of 6, retail with a score of 0, and construction with a score of 4, I would want the output to be a dict (or something similar) that would contain:
programmer, 6
construction, 4
nurse, 3
retail, 0
or, even better, could I sort it by the values but get the output as a vector with just the jobs? then reference that vector later in my code?
this works in your specific case:
jobs = Dict("nurse"=>3, "construction"=>4, "programmer"=>6, "retail"=>0)
jobpairs = collect(jobs)
jobvalues = collect(values(jobs))
sind = sort(collect(values(jobs)), rev=true)
julia> sortedNames = [jobpairs[i] for i in indexin(sind, jobvalues)]
4-element Array{Any,1}:
"programmer"=>6
"construction"=>4
"nurse"=>3
"retail"=>0
if two keywords have the same value, we need do more work to deal with indices.
UPDATE:
as Matt suggested in the comment below, we should use sortperm rather than indexin which won't work if the dict has at least two keywords that have the same value.
jobs = Dict("nurse"=>3, "construction"=>4, "foo"=>3, "programmer"=>6, "retail"=>0)
jobpairs = collect(jobs)
jobvalues = collect(values(jobs))
sind = sortperm(collect(values(jobs)), rev=true)
julia> sortedNames = [jobpairs[i].first for i in sind]
5-element Array{Any,1}:
"programmer"
"construction"
"foo"
"nurse"
"retail"
Sorting algorithm with less code, but I don't know about the performance and you would not have a dict as result:
sort(collect(jobs),by=x->x[2],rev=true)
Currently I think the recommended way to do it is:
julia> using DataStructures
julia> jobs = Dict("nurse"=>3, "construction"=>4, "programmer"=>6, "retail"=>0)
Dict{String,Int64} with 4 entries:
"programmer" => 6
"retail" => 0
"construction" => 4
"nurse" => 3
julia> sort!(OrderedDict(jobs), byvalue=true, rev=true)
OrderedDict{String,Int64} with 4 entries:
"programmer" => 6
"construction" => 4
"nurse" => 3
"retail" => 0
In this way you get a dictionary as you wanted, but it is OrderedDict so it can be sorted as you see.
I have a hash
h = {}
h.compare_by_identity
h[2.51] = 1
h1[2.51] = 2
Edit: h1[2.51] = 2 should be h[2.51] = 2
it is ok with duplicate key. But when i use
Hash[h.sort]
it return only one value with key like
{2.51=>2}
is there any way to get the two values from the hash in sorted order?
Starting with ruby version 2.0 the key 2.51 is actually the same object (because of ruby internal caching) in both assignments. Try to output 2.51.object_id for both cases and it will output the same id.
Since it can't be done with floats, turn them into strings:
h = {}
h.compare_by_identity
h[2.51.to_s] = 2
h[2.51.to_s] = 1
p h.sort # => [["2.51", 1], ["2.51", 2]]