Suppose I have a DataFrame in Julia and typeof((df[:,:col])) returns Array{Union{Missing, Float64},1}. How do I check the types within Union{Missing, Float64} to, for example, see if Float64 is in that Union, or to make sure that there are no String values in that Union?
You can use the subtype operator:
T1 = Union{Missing, Float64}
Float64 <: T1 # true
String <: T1 # false
This is because Float64 is a subtype of the union, whereas String is not (since it's not in the union).
If you're defining a method to dispatch on it, you could go a step further:
function doSomething(arr::Vector{Union{Missing, T}}) where T <: Float64
# do something
end
Related
I use lots of Int32s in my code because I have some large arrays of those. But for some x::Int32 we have typeof(x+1) == Int64 since numeric literals are Int64 by default (I have to use 64bit Julia to handle my arrays). The problem is, if I have some function f(x::Int32) then f(x+1) will method error. I don't want to implement a f(x::Int64) = f(convert(Int32, x)) for almost every function and want to use concrete types for type stability. Currently, I simply have expressions like x + Int32(1) all over my code which looks really cluttered. For other types we have shorthands, i.e., 1.f0 gives me a Float32 and big"1" a BigInt. Is there something similar for Int32?
Since you explicitly mention the big_str macro (big"") you can easily define a similar macro for Int32 (the same way the uint128_str and int128_str is defined):
macro i32_str(s)
parse(Int32, s)
end
julia> typeof(i32"1")
Int32
this might still clutter your code too much so alternatively you could exploit that a number followed by a name is multiplication:
struct i32 end
(*)(n, ::Type{i32}) = Int32(n)
julia> typeof(1i32)
Int32
You can make a macro to replace every literal integer with an Int32, a bit like what ChangePrecision.jl does for floats. A very quick first attempt is:
julia> macro literal32(ex)
esc(literal32(ex))
end;
julia> literal32(ex::Expr) = Expr(ex.head, literal32.(ex.args)...);
julia> literal32(i::Int) = Int32(i);
julia> literal32(z) = z; # ignore Symbol, literal floats, etc.
julia> #literal32 [1,2] .+ 3
2-element Vector{Int32}:
4
5
julia> #literal32 function fun(x::AbstractVector)
x[1] + 2 # both 1 and 2 are changed
end
fun (generic function with 1 method)
julia> fun(Int32[3,4]) |> typeof
Int32
One place this may have unexpected consequences is literal type parameters:
julia> #literal32([1,2,3]) isa Array{Int32,1}
true
julia> #literal32 [1,2,3] isa Array{Int32,1}
false
Another is that x^2 will not use Base.literal_pow, e.g. #literal32 Meta.#lower pi^2.
What if you say:
# Or, a::Int32 = 1
julia> a = Int32(1)
1
julia> b::Int32 = a+2
3
julia> typeof(b)
Int32
julia> f(b)
...
This question already has answers here:
Julia: what does the "<:" symbol mean?
(2 answers)
Closed 2 years ago.
Can anyone help me with this code:
struct GenericPoint{T<:Real}
x::T
y::T
end
What is meaning of <: in {T<:Real} in Julialang?
Let me begin by saying that the punctuation page of the manual is a handy way to search for such operators, which are otherwise very difficult to look for using a search engine.
In the specific case of <:, we find this page, with the relevant documentation for essential operators.
There are (at least) 3 contexts where A <: B might be used, and in all of them this expresses the idea that A is a subtype of B.
as a predicate, A <: B returns true if and only if all values of type A are also of type B:
julia> Int <: Number
true
julia> Int <: AbstractString
false
in a type definition, this declares that the newly defined type is a subtype of an existing (abstract) type:
# `Foo` is declared to be a subtype of `Number`
struct Foo <: Number
end
as a type-parameter constraint (like in your example), T <: Real expresses the idea that type parameter T can be any subtype of Real:
julia> struct GenericPoint{T<:Real}
x::T
y::T
end
# Works because 1 and 2 are of type Int, and Int <: Real
julia> GenericPoint(1, 2)
GenericPoint{Int64}(1, 2)
# Does not work because "a" and "b" are of type String,
# which is not a subtype of Real
julia> GenericPoint("a", "b")
ERROR: MethodError: no method matching GenericPoint(::String, ::String)
Stacktrace:
[1] top-level scope at REPL[5]:1
Note that the use for type-parameter constraints is not restricted to the definition of parametric types, but also applies to function/method definitions:
julia> foo(x::Vector{T}) where {T<:Number} = "OK"
foo (generic function with 1 method)
# OK because:
# - [1,2,3] is of type Vector{Int}, and
# - Int <: Number
julia> foo([1, 2, 3])
"OK"
# Incorrect because:
# - ["a", "b", "c"] is of type Vector{String}, but
# - String is not a subtype of Number
julia> foo(["a", "b", "c"])
ERROR: MethodError: no method matching foo(::Array{String,1})
Is there a way to create a parametric type which represents a heterogeneous tuple of variable length, where each element of the tuple is a MVector, such that the MVector's can have different length but they contain the same numerical type. So in pseudo code I would like to have something like this:
using StaticArrays
struct MyType{T, N1, N2, N3, ...}
data::Tuple{MVector{N1, T}, MVector{N2, T}, MVector{N3, T}, ...}
end
I can of course make a more specific type like:
struct MyType3{T, N1, N2, N3}
data::Tuple{MVector{N1, T}, MVector{N2, T}, MVector{N3, T}}
end
But I would like to generalise to an tuple of arbitrary length.
If you don't need the "variadic type arguments" N1...Nk explicitely, you can use a tuple of Vararg of some UnionAll types:
julia> MyType3{T} = Tuple{Vararg{MVector{M, <:T} where M}}
Tuple{Vararg{MArray{Tuple{M},#s14,1,M} where #s14<:T where M,N} where N} where T
julia> (MVector{2}([1,2]), MVector{3}([1,2,3])) isa MyType3{Int}
true
julia> (MVector{2}([1,2]), MVector{3}([1,2,3])) isa MyType3{Number}
true
julia> (MVector{2}([1,2]), MVector{3}([1,2,3])) isa MyType3{String}
false
julia> (MVector{2}([1,2]), MVector{3}([1,2,3])) isa MyType3
true
julia> (MVector{2}(["a", "b"]), MVector{3}([1,2,3])) isa MyType3
true
Or maybe like this, where you have an explicit tuple of the size types:
julia> struct MyType7{T, Ns<:Tuple, D}
data::D
function MyType7(vecs::Vararg{MVector{M, T} where M}) where {T}
Ns = [typeof(v).parameters[4] for v in vecs]
new{T, Tuple{Ns...}, typeof(vecs)}(vecs)
end
end
julia> MyType7(MVector{2}([1,2]), MVector{3}([1,2,3]))
MyType7{Int64,Tuple{2,3},Tuple{MArray{Tuple{2},Int64,1,2},MArray{Tuple{3},Int64,1,3}}}(([1, 2], [1, 2, 3]))
julia> typeof(ans)
MyType7{Int64,Tuple{2,3},Tuple{MArray{Tuple{2},Int64,1,2},MArray{Tuple{3},Int64,1,3}}}
But this is now a kind of a hack, since we use parameters to reflect on the type arguments at runtime. If you use this variant, be sure to know what you're doing (which I wouldn't quite say about myself), and to benchmark it (or maybe make it #generated?).
I am looking to get the types of the fields within a struct in order to set the field values correspondingly. Some data types initialise values on instantiation (e.g. Int64, Float64), whereas other types initialise to #undef (e.g. String, Array). Whilst typeof(getfield()) works for the former types, it throws UndefRefError for the latter:
julia> mutable struct MyStruct
a::Int64
b::String
MyStruct() = new()
end
julia> foo = MyStruct()
MyStruct(0, #undef)
julia> typeof(getfield(foo, :a))
Int64
julia> typeof(getfield(foo, :b))
ERROR: UndefRefError: access to undefined reference
Stacktrace:
[1] top-level scope at none:0
Is there is way to get the type of an uninitialised variable or does #undef indicate the distinct lack of a type? Alternatively, is it possible to initialise default values using the inner constructor? e.g.
julia> mutable struct MyStruct
a::Int64
b::String
MyStruct() = new(b = "")
end
You're looking for the fieldtype function:
julia> fieldtype(MyStruct, :a)
Int64
julia> fieldtype(MyStruct, :b)
String
To your other question, you surely can initialize fields.
mutable struct MyStruct
a::Int64
b::String
MyStruct() = new(0,"") # will initialize a as 0 and b as ""
end
Just a follow-on, you can get a tuple of all field types with fieldtypes:
julia> fieldtypes(MyStruct)
(Int64, String)
Let's say I have the Union:
SomeUnion = Union{Int, String}
Is there a method to extract a collection of types that form this union? For example ....
union_types(SomeUnion) # => [Int, String]
just write down a simple example here:
a = Union(Int,String)
function union_types(x)
return x.types
end
julia> union_types(a)
(Int64,String)
you can store the result into an array if you want:
function union_types(x)
return collect(DataType, x.types)
end
julia> union_types(a)
2-element Array{DataType,1}:
Int64
String
UPDATE: use collect as #Luc Danton suggested in comment below.
For Julia 0.6, NEWS.md states that "Union types have two fields, a and b, instead of a single types field". Additionally, "Parametric types with "unspecified" parameters, such as Array, are now represented as UnionAll types instead of DataTypes".
Thus, to get the types as a tuple, one can do
union_types(x::Union) = (x.a, union_types(x.b)...)
union_types(x::Type) = (x,)
If you want an array, just collect the tuple
julia> collect(union_types(Union{Int, Float64, String, Array}))
4-element Array{Type,1}:
Int64
Float64
String
Array
Base.uniontypes is not documented (as of julia-1.6.1), so use with care.
But it works:
julia> SomeUnion = Union{Int, String}
Union{Int64, String}
julia> Base.uniontypes(SomeUnion)
2-element Vector{Any}:
Int64
String