How to sort a hash with duplicate key? - ruby

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]]

Related

How do I check if a dictionary has a key in it in Julia?

Suppose I have a Dict object and a key value and I want to see if there's already an entry in the dictionary for that key? How do I do this?
There are a few ways to do this. Suppose this is your dictionary:
d = Dict(
"aardvark" => 1,
"bear" => 2,
"cat" => 3,
"dog" => 4,
)
If you have a key you can check for its presence using the haskey function:
julia> haskey(d, "cat")
true
julia> haskey(d, "zebra")
false
A slightly fancier way to check this is to check if the key is in the set of keys returned by calling keys(d):
julia> ks = keys(d)
Base.KeySet for a Dict{String,Int64} with 4 entries. Keys:
"aardvark"
"bear"
"cat"
"dog"
julia> "cat" in ks
true
julia> "zebra" in ks
false
Finally, it's fairly common that you want to get the value associated with a key if it is present in the dictionary. You can do that as a separate step by doing d[k] after checking that k is present in keys(d) but that involves an additional dictionary lookup. Instead, if there is some sentinel value that you know cannot be a value in your dictionary, such as nothing, then you can use the get function to look up the key with a default:
v = get(d, k, nothing)
if v !== nothing
# keys(d) contains k
end
If you know nothing about the kinds of values that d can map keys to, this is not a safe option since it could be the case that the pair k => nothing is present in d.
Ok not exactly an answer but still relevant to the discussion, something I learnt recently about julia dictionary accessor method that has made my life a lot easier.
val = get(dict, "key", nothing)
also has a version that creates the dictionary entry and sets it to the default value if it does not already exist
val = get!(dict, "key", nothing)
which does away with writing a lot of blocks like this
if !haskey(dict, "key")
dict["key"] = nothing
end
val = dict["key"]
so now instead of littering your code with key checks and dictionary value initialization blocks you can use get! instead.

How to access key-value tuples in forward/reverse order for Dict and SortedDict? - Julia

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)

How to make a number argument a variable?

How do I make a number argument a variable?
For example:
Snippet 1:
a=1
a_7 = a+6
alphabet = "ABCDEFGHIJKLMNOPQRSTUVQXYZ"
letter_7 = alphabet.slice[a_7..a_7]
Snippet 2:
alphabet = "ABCDEFGHIJKLMNOPQRSTUVQXYZ"
letter_7 = alphabet.slice[7..7]
I would like to make snippet 1 have the same outcome as snippet 2, with a variable as the arguments within slice action. Is there a way to do this?
So your issue come from the fact that you are using the slice method without any arguments. You can not use [] with the slice method. To make this work, you need to change [] to ()
letter_7 = alphabet.slice(7..7)
This will actually return H as the result, because arrays index start at 0, so to get the 7th letter, you will need to slice at index 6.
letter_7 = alphabet.slice(6..6) #=> 'G'
Or, you can just use the [] method on the string itself.
letter_7 = alphabet[6] #=> 'G'
Of course, you can replace the index values with variables, as long as the variables are set to integers.
a = 6
letter_7 = alphabet[a] #=> 'G'

Redis: sorting hash "fields" in alpha

I am trying to sort the "fields" in a hash.
For example,
mykey, cde, firstone
mykey, abcde, secondone
mykey, bcde, thirdone
I want to sort the fields(cde, abcde, bcde) in alphabet order, but there is no way to do so.. If anyone knows about this, please help me.
If there is no way to solve this, I am thinking about changing names of key&values.. and use zadd instead of hash. If you have a better solution, please give me an advice here.
Hash field names are not sortable-by easily - there is no native command to do so and the order in which fields are returned (e.g. with HGETALL) is for all intents and purposes random.
While Sorted Sets are preferable when it comes to sorting, you could work around this with use of a Lua script that will perform lexical sorting the Hash's fields. For example:
$ cat hashsort.lua
local r = redis.call('HGETALL',KEYS[1])
local t = {}
for i=1,#r,2 do
t[#t+1] = { field = r[i], value = r[i+1] }
end
table.sort(t, function(a,b) return a.field < b.field end)
r = {}
for _, v in pairs(t) do
r[#r+1] = v.field
r[#r+1] = v.value
end
return r
$ redis-cli HMSET hash z 99 ee 55 e 5 a 1 b 2 ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ justsomethinglongsohashmaxzipwillbeexceeded
OK
$ redis-cli --eval hashsort.lua hash
1) "a"
2) "1"
3) "b"
4) "2"
5) "e"
6) "5"
7) "ee"
8) "55"
9) "z"
10) "99"
11) "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
12) "justsomethinglongsohashmaxzipwillbeexceeded"

Create a two separate arrays from existing array in ruby

I have a array of n elements say
snaps = ["s-1","s-2","s-3","s-4",..."s-n-2","s-n-1","s-n"]
now I want to create two diff array such that one array contains last 5 elements and another contains remaining elements.For example
snap1 = ["s-1","s-2","s-3","s-4",...]
snap2 = ["s-n-5","s-n-3","s-n-2","s-n-1","s-n"]
How can I do this.
snap1 = snaps.dup
snap2 = snap1.pop(5)
snap2 = snaps[-5, 5]
Or
snap2 = snaps.last(5) # As suggested my BroiSatse
will give you an array with the last 5 elements
For the remaining, you can do
snap1 = snaps[0..-6]
You can use slice! to create the two arrays:
snaps = ["s-1","s-2","s-3","s-4","s-n-5","s-n-3","s-n-2","s-n-1","s-n"]
snap2 = snaps.slice!(-5..-1)
# => ["s-n-5", "s-n-3", "s-n-2", "s-n-1", "s-n"]
snaps
# => ["s-1", "s-2", "s-3", "s-4"]

Resources