Finding the set of keys with the same value in a Dictionnary

juliapro

#1

Hello, I know that a dictionary is not intended to be used this way but I’d like to know if it exists some function that allows me to get all the keys that have the same value in a dict. For example :

d = Dict( "dinner 1" => "carrot", "dinner 2" => "rice", "dinner 3" => "carrot") 

Then, if I want to find all the keys that contains “carrot” I would have : [ “dinner 1”, “dinner 3”]

Thanks in advance.


#2
julia> [k for (k,v) in d if v=="carrot"]
2-element Array{String,1}:
 "dinner 1"
 "dinner 3"

#3
dinners = Dict( "dinner 1" => "carrot", "dinner 2" => "rice", "dinner 3" => "carrot")
menus = Dict()
for (k, v) in dinners
    if haskey(menus, v)
        push!(menus[v],k)
    else
        menus[v] = [k]
    end
end
julia> menus
Dict{Any,Any} with 2 entries:
  "rice"   => String["dinner 2"]
  "carrot" => String["dinner 1", "dinner 3"]

#4

Alternatively, you can use filter() to return your results as a dictionary. For example:

result = filter((k,v)->v == "carrot",d)

Use keys(result) if you want the keys. If you want to find all of the keys that match unique values, you can also do this:

f(m,d) = filter((k,v)->v == m,d)
results = map(x->f(x,d),unique(values(d)))

f(m,d) makes the filter function more general and map() allows you to apply it to every unique value in the dictionary. With this method, each unique value is assigned to a distinct dictionary in the result array, which may or may not suit your purposes.


#5

Thanks a lot for your suggestions. They work very well . However, I tried to use it in another version of a dictionary that looks like as follows :

d = Dict( "dinner 1" => ["carrot", "beans"], "dinner 2" => "rice", "dinner 3" => "carrot") 

In this way, we cannot get the correct keys that contains “carrot” because the instructions see the value together (the value of “dinner 1” it’s the full array [“carrot”, “beans”] and not separated), for example, the instruction

key_value = [k for (k,v) in d if v=="carrot"]

It will return only the key “dinner 3”. Do you think, it’s a way to get the values individually, even if the value associated to a key it’s a array of string ? I’d like to get the answer : “dinner 3” and “dinner 1”. I have this problem in other codes but I couldn’t find a way to deal with it. Thanks in advance for your help.


#6

Try something like this:

julia> has(x::String, y) = x == y
has (generic function with 1 method)

julia> has(x::AbstractArray, y) = y in x
has (generic function with 2 methods)

julia> key_value = [k for (k,v) in d if has(v, "carrot")]
2-element Array{String,1}:
 "dinner 1"
 "dinner 3"

#7

Thanks a lot. Your function helped me a lot. My dict contains SubString{String} types and I’ve tried to use the following command to try to get these values :

has(x::SubString{String}, y) = y in x 

But unfortunately the function doesn’t return as expected. It keeps getting only the values that are String. Have you any idea why this behavior ?


#8

SubString{String} <: String is false, so you could either use has(x::AbstractString, y) = x == y or just has(x, y) = x == y.


#9

Thanks for your answer. Unfortunately, It didn’t work. In fact, I have a dictionnary with informations organized like that :

  "ID3" => Any["Heating", SubString{String}["Cold"]] 
 "ID4" => Any["Elec", SubString{String}["Heating", "Cold"]]

The function “has” only look in the first part of the values. It never look at the second part where we have the SubString. I use SubString because the two parts of the values represents 2 different things, like IN = Heating and OUT = Cold. When I have 2 outputs, I wrote this using the symbol & and to get the 2 values I used the split function. That’s why I found myself with this type of SubString. I’ve tried many options but it still doens’t look at the SubString part.


#10

Right, then just recursively call has:

julia> d = Dict( "dinner 1" => ["apple", ["carrot", "beans"]], "dinner 2" => "rice", "dinner 3" => "carrot")
Dict{String,Any} with 3 entries:
  "dinner 2" => "rice"
  "dinner 1" => Any["apple", ["carrot", "beans"]]
  "dinner 3" => "carrot"

julia> has(x::AbstractString, y) = x == y
has (generic function with 1 methods)

julia> has(x::AbstractArray, y) = any(has(i, y) for i in x)
has (generic function with 2 methods)

julia> key_value = [k for (k,v) in d if has(v, "carrot")]
2-element Array{String,1}:
 "dinner 1"
 "dinner 3"

#11

Thanks a lot for your incredible help! Problem solved :grinning::grinning::grinning: