Extracting parameter types in Julia
Asked Answered
Q

5

10

Suppose I write a function in Julia that takes a Dict{K,V} as an argument, then creates arrays of type Array{K,1} and Array{V,1}. How can I extract the types K and V from the Dict object so that I can use them to create the arrays?

Quorum answered 8/1, 2014 at 9:11 Comment(0)
E
9

Sven and John's answers are both quite right. If you don't want to introduce method type parameters the way John's code does, you can use the eltype function:

julia> d = ["foo"=>1, "bar"=>2]
["foo"=>1,"bar"=>2]

julia> eltype(d)
(ASCIIString,Int64)

julia> eltype(d)[1]
ASCIIString (constructor with 1 method)

julia> eltype(d)[2]
Int64

julia> eltype(keys(d))
ASCIIString (constructor with 1 method)

julia> eltype(values(d))
Int64

As you can see, there are a few ways to skin this cat, but I think that eltype(keys(d)) and eltype(values(d)) are by far the clearest and since the keys and values functions just return immutable view objects, the compiler is clever enough that this doesn't actually create any objects.

Elegy answered 8/1, 2014 at 16:15 Comment(4)
Thanks everyone. I decided to accept this answer because it was the most general (will also work on other iterable data structures).Quorum
eltype(d) now returns Pair{ASCIIString,Int64} and eltype(d)[1] no longer works. (Julia v0.4)Emelina
keytype and valtype are built-ins as of v0.4, and take the place of eltype(d)[1] and eltype(d)[2], respectively.Semblable
Noting that as of v0.6, eltype(d)[1] no longer works, at least for dictionaries. I get the error: MethodError: Cannot `convert` an object of type Int64 to an object of type Pair{String,Int64}, and the thing returned from eltype() is a Pair{String,Int}. That said, eltype(keys(d)) still works as expectedOstracism
R
8

If you're writing a function that will do this for you, you can make the types a parameter of the function, which may save you some run-time lookups:

julia> function foo{K, V}(d::Dict{K, V}, n::Integer = 0)
          keyarray = Array(K, n)
          valarray = Array(V, n)
          # MAGIC HAPPENS
          return keyarray, valarray
       end
foo (generic function with 2 methods)

julia> x, y = foo(["a" => 2, "b" => 3])
([],[])

julia> typeof(x)
Array{ASCIIString,1}

julia> typeof(y)
Array{Int64,1}
Remise answered 8/1, 2014 at 15:59 Comment(0)
K
3

You can use keys and values in combination with typeof:

# an example Dict{K, V}
d = Dict{Int64, ASCIIString}()

# K
typeof(keys(d))
Array{Int64,1}

# V
typeof(values(d))
Array{ASCIIString,1}
Kozak answered 8/1, 2014 at 13:35 Comment(1)
Might be worth noting that keys and values now return iterators, not arrays. You need to add in a call to collect in newer versions of Julia to get an array out.Remise
S
2

If you are just interested in the types, you can use eltype(d), or define even more specific functions

keytype{K}(d::Dict{K}) = K
valuetype{K,V}(d::Dict{K,V}) = V

and find the type immediately through

keytype(d)
valuetype(d)

As far as I understand, this should be pretty efficient because the compiler can deduce most of this at compile time.

Sanative answered 26/11, 2014 at 8:20 Comment(0)
E
0

For iterables, the eltype approach that is already given in other answers works well enough. E.g.

julia> d = Dict(:a => 1, :b => 2)
Dict{Symbol, Int64} with 2 entries:
  :a => 1
  :b => 2

julia> K, V = eltype(keys(d)), eltype(values(d))
(Symbol, Int64)

julia> K
Symbol

julia> V
Int64

This approach is generalisable to all iterables. However I would like to offer another approach which will generalise to other kinds of object (and still doesn't use the method type signature approach):

julia> d = Dict(:a => 1, :b => 2)
Dict{Symbol, Int64} with 2 entries:
  :a => 1
  :b => 2

julia> typeof(d)
Dict{Symbol, Int64}

julia> K, V = typeof(d).parameters
svec(Symbol, Int64)

julia> K
Symbol

julia> V
Int64

You can see that the Dict{Symbol, Int64} type has a field parameters which you can unpack to obtain the type parameters. This works on structs too:

julia> struct MyStruct{S, T}
           a::S
           b::T
       end

julia> x = MyStruct(1, 1.0)
MyStruct{Int64, Float64}(1, 1.0)

julia> S, T = typeof(x).parameters
svec(Int64, Float64)

julia> S
Int64

julia> T
Float64
Eremite answered 1/7, 2022 at 8:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.