Julia: concatenate string and integer - julia

What is the simplest way in Julia to concatenate a string and an integer value? I would like to do something like:
julia> foo = "test: "
"test: "
julia> bar = 3
3
julia> foobar = foo * bar
ERROR: `*` has no method matching *(::ASCIIString, ::Int64)

I'm not terribly familar with Julia, but I believe you'd be better off with string interpolation:
"test: $bar"
Or alternately:
string("test: ", bar)
Or, if you did want to use the * operator, I believe you'd want:
"test: " * string(bar)

You can extend the * generic function with a new method, using multiple dispatch to the Union{String, Number} type:
julia> VERSION
v"0.6.0-rc1.0"
julia> *
* (generic function with 181 methods)
julia> const StrNum = Union{String, Number}
Union{Number, String}
julia> import Base: *
julia> Base.:*(x::StrNum, y::StrNum) = string(x, y)
julia> 4 * "2"
"42"
julia> "4" * 2
"42"

Related

Filtering a dictionary in julia

I want to filter a dictionary using filter() function but I am having trouble with it. What I wish to accomplish is, to return the key for some condition of the value. However I am getting a method error
using Agents: AbstractAgent
# Define types
mutable struct Casualty <: AbstractAgent
id::Int
ts::Int
rescued::Bool
function Casualty(id,ts; rescued = false)
new(id,ts,rescued)
end
end
mutable struct Rescuer <: AbstractAgent
id::Int
actions::Int
dist::Float64
function Rescuer(id; action = rand(1:3) , dist = rand(1)[1])
new(id,action,dist)
end
end
cas1 = Casualty(1,2)
cas2 = Casualty(2,3)
resc1 = Rescuer(3)
agents = Dict(1=> cas1, 2 => cas2, 3 => resc1)
Now to filter
filter((k,v) -> v isa Casualty, agents)
# ERROR: MethodError: no method matching (::var"#22#23")(::Pair{Int64, AbstractAgent})
# what I truly wish to achieve is return the key for some condition of the value
filter((k,v) -> k ? v isa Casualty : "pass", agents)
# ofcourse I am not sure how to "pass" using this format
Any idea how I can achieve this. Thanks
For dictionaries filter gets a key-value pair, so do either (destructuring Pair):
julia> dict = Dict(1=>"a", 2=>"b", 3=>"c")
Dict{Int64, String} with 3 entries:
2 => "b"
3 => "c"
1 => "a"
julia> filter(((k,v),) -> k == 1 || v == "c", dict)
Dict{Int64, String} with 2 entries:
3 => "c"
1 => "a"
or for example (getting Pair as a whole):
julia> filter(p -> first(p) == 1 || last(p) == "c", dict)
Dict{Int64, String} with 2 entries:
3 => "c"
1 => "a"
julia> filter(p -> p[1] == 1 || p[2] == "c", dict)
Dict{Int64, String} with 2 entries:
3 => "c"
1 => "a"
EDIT
Explanation why additional parentheses are needed:
julia> f = (x, y) -> (x, y)
#1 (generic function with 1 method)
julia> g = ((x, y),) -> (x, y)
#3 (generic function with 1 method)
julia> methods(f)
# 1 method for anonymous function "#1":
[1] (::var"#1#2")(x, y) in Main at REPL[1]:1
julia> methods(g)
# 1 method for anonymous function "#3":
[1] (::var"#3#4")(::Any) in Main at REPL[2]:1
julia> f(1, 2)
(1, 2)
julia> f((1, 2))
ERROR: MethodError: no method matching (::var"#1#2")(::Tuple{Int64, Int64})
Closest candidates are:
(::var"#1#2")(::Any, ::Any) at REPL[1]:1
julia> g(1, 2)
ERROR: MethodError: no method matching (::var"#3#4")(::Int64, ::Int64)
Closest candidates are:
(::var"#3#4")(::Any) at REPL[2]:1
julia> g((1, 2))
(1, 2)
As you can see f takes 2 positional argument, while g takes one positional argument that gets destructured (i.e. the assumption is that argument passed to g is iterable and has at least 2 elements).
See also https://docs.julialang.org/en/v1/manual/functions/#Argument-destructuring.
Now comes the tricky part:
julia> h1((x, y)) = (x, y)
h1 (generic function with 1 method)
julia> methods(h1)
# 1 method for generic function "h1":
[1] h1(::Any) in Main at REPL[1]:1
julia> h2 = ((x, y)) -> (x, y)
#1 (generic function with 1 method)
julia> methods(h2)
# 1 method for anonymous function "#1":
[1] (::var"#1#2")(x, y) in Main at REPL[3]:1
In this example h1 is a named function. In this case it is enough to just wrap arguments in extra parentheses to get destructuring behavior. For anonymous functions, because of how Julia parser works an extra , is needed - if you omit it the extra parentheses are ignored.
Now let us check filter docstring:
filter(f, d::AbstractDict)
Return a copy of d, removing elements for which f is false.
The function f is passed key=>value pairs.
As you can see from this docstring f is passed a single argument that is Pair. That is why you need to use either destructuring or define a single argument function and extract its elements inside the function.
The right syntax is:
filter(((k,v),) -> v isa Casualty, agents)
which prints
julia> filter(((k,v),) -> v isa Casualty, agents)
Dict{Int64, AbstractAgent} with 2 entries:
2 => Casualty(2, 3, false)
1 => Casualty(1, 2, false)
About the problem of only getting involved keys... I have no idea beside:
julia> filter(((k,v),) -> v isa Casualty, agents) |> keys
which prints
julia> filter(((k,v),) -> v isa Casualty, agents) |> keys
KeySet for a Dict{Int64, AbstractAgent} with 2 entries. Keys:
2
1

How to pass a function typesafe in julia

Let's say, I want to pass a function to another function:
function foo()
return 0;
end
function bar(func)
return func();
end
print(bar(foo));
But you can make functions typesafe:
function func(t::Int)
print(t);
end
func(0); #produces no error
func("Hello world"); #produces an error
I didn't found out, how I combine both, that means, how can I explicitly define a parameter of bar, like func, to be a function, possibly with certain input / output argument types.
Thanks in advance for any help.
If I understand you correctly you want to make sure the passed function returns a specific type? The simplest thing is to just typeassert the return value at runtime:
julia> function f(func)
val = func()::Int # Error if the return value is not of type Int
return val
end
f (generic function with 1 method)
julia> f(() -> 1)
1
julia> f(() -> 1.0)
ERROR: TypeError: in typeassert, expected Int64, got Float64
Stacktrace:
[1] f(::var"#7#8") at ./REPL[5]:2
[2] top-level scope at REPL[8]:1
Alternatively you can use the FunctionWrappers.jl package (which will convert to the specified return type, or error if the conversion is not possible):
julia> using FunctionWrappers: FunctionWrapper
julia> function f(func::FunctionWrapper{Int,<:Tuple})
val = func()
return val
end;
julia> function f(func)
fw = FunctionWrapper{Int,Tuple{}}(func)
return f(fw)
end;
julia> f(() -> 1)
1
julia> f(() -> 1.0) # Can convert to Int
1
julia> f(() -> 1.2) # Can not convert to Int
ERROR: InexactError: Int64(1.2)
A function is of type Function. You can easily check this:
julia> foo() = 1;
julia> T = typeof(foo)
typeof(foo)
julia> supertype(T)
Function
julia> foo isa Function
true
This will not necessarily cover all callable types, as you can make any type callable:
julia> struct Callable end
julia> (::Callable)(x::Number) = x + one(x)
julia> callable = Callable()
Callable()
julia> callable(5)
6
julia> callable isa Function
false

Specializing method calls in order in meta-programming

I have issue after calling my macro:
#introspectable square(x) = x * x
Then when calling
square(3)
i should be able to get 9, cause the function call has been specialized to execute an attribute of the structure which is Julia code, however when I enter the macro, the code seems to be directly evaluated.
What i have tried:
struct IntrospectableFunction
name
parameters
native_function
end
(f::IntrospectableFunction)(x) = f.native_function(x)
macro introspectable(expr)
name = expr.args[1].args[1]
parameters = tuple(expr.args[1].args[2:end]...)
body = expr.args[2].args[2]
:( global $name = IntrospectableFunction( :( name ), $parameters, :( body ) ))
end
#introspectable square(x) = x * x
square(3)
The answer should be 9 , however i get "Object of type symbol are not callable ". However if i replace :( body ) with x -> x * x i get the desired result, my objective is generalizing the macro-call.
I usually find it easier to work with expressions in macros (it is not the shortest way to write things, but, from my experience, it is much easier to control what gets generated).
Therefore I would rewrite your code as:
macro introspectable(expr)
name = expr.args[1].args[1]
parameters = expr.args[1].args[2:end]
anon = Expr(Symbol("->"), Expr(:tuple, parameters...), expr.args[2].args[2])
constr = Expr(:call, :IntrospectableFunction, QuoteNode(name), Tuple(parameters), anon)
esc(Expr(:global, Expr(Symbol("="), name, constr)))
end
Now, as you said you wanted generality I would define your functor like this:
(f::IntrospectableFunction)(x...) = f.native_function(x...)
(in this way you allow multiple positional arguments to be passed).
Now let us test our definitions:
julia> #introspectable square(x) = x * x
IntrospectableFunction(:square, (:x,), getfield(Main, Symbol("##3#4"))())
julia> square(3)
9
julia> #macroexpand #introspectable square(x) = x * x
:(global square = IntrospectableFunction(:square, (:x,), ((x,)->x * x)))
julia> #introspectable toarray(x,y) = [x,y]
IntrospectableFunction(:toarray, (:x, :y), getfield(Main, Symbol("##5#6"))())
julia> toarray("a", 10)
2-element Array{Any,1}:
"a"
10
julia> #macroexpand #introspectable toarray(x,y) = [x,y]
:(global toarray = IntrospectableFunction(:toarray, (:x, :y), ((x, y)->[x, y])))
julia> function localscopetest()
#introspectable globalfun(x...) = x
end
localscopetest (generic function with 1 method)
julia> localscopetest()
IntrospectableFunction(:globalfun, (:(x...),), getfield(Main, Symbol("##9#10"))())
julia> globalfun(1,2,3,4,5)
(1, 2, 3, 4, 5)
julia> function f()
v = 100
#introspectable localbinding(x) = (v, x)
end
f (generic function with 1 method)
julia> f()
IntrospectableFunction(:localbinding, (:x,), getfield(Main, Symbol("##11#12")){Int64}(100))
julia> localbinding("x")
(100, "x")
(note that it is useful to use #macroexpand to make sure our macro works as expected)
EDIT - how to handle a minimal multiple dispatch
I am writing a non-macro example because it is related to the data structure:
Use e.g. such a definition:
struct IntrospectableFunction
name::Symbol
method_array::Vector{Pair{Type{<:Tuple}, Function}}
end
function (f::IntrospectableFunction)(x...)
for m in f.method_array
if typeof(x) <: first(m)
return last(m)(x...)
end
end
error("signature not found")
end
and now you can write:
julia> square = IntrospectableFunction(:square, [Tuple{Any}=>x->x*x,Tuple{Any,Any}=>(x,y)->x*y])
IntrospectableFunction(:square, Pair{DataType,Function}[Tuple{Any}=>##9#11(), Tuple{Any,Any}=>##10#12()])
julia> square(3)
9
julia> square(2,3)
6
Keep in mind that the approach I present is not perfect and universal - it just serves to give a very simple example how you could do it.

A function or a macro for retrieving attributes of annotated strings

I have strings with annotated attributes. You can think of them as XML-document strings, but with custom syntax of annotation.
Attributes in a string are encoded as follows:
#<atr_name>=<num_of_chars>:<atr_value>\n
where
<atr_name> is a name of the attribute
<atr_value> is a value of the attribute
<num_of_chars> is a character length of the <atr_value>
That is attribute name is prefixed with # and postfixed with =, then followed by number that indicates number of characters in the value of the attribute, then followed by :, then followed by the attribute's value itself, and then followed by with newline character \n
Here is one example:
julia> string_with_attributes = """
some text
...
#name=6:Azamat
...
#year=4:2016
...
some other text
"""
Now I want to write a function or a macro that would allow me to call as:
julia> string_with_attributes["name"]
"Azamat"
julia> string_with_attributes["year"]
"2016"
julia>
Any ideas on how to do this?
Following #Gnimuc answer, you could make your own string macro AKA non standard string literal if that suit your needs, ie:
julia> function attr_str(s::S)::Dict{S, S} where {S <: AbstractString}
d = Dict{S, S}()
for i in eachmatch(r"(?<=#)\b.*(?==).*(?=\n)", s)
push!(d, match(r".*(?==)", i.match).match => match(r"(?<=:).*", i.match).match)
end
push!(d, "string" => s)
return d
end
attr_str (generic function with 1 method)
julia> macro attr_str(s::AbstractString)
:(attr_str($s))
end
#attr_str (macro with 1 method)
julia> attr"""
some text
dgdfg:dgdf=ert
#name=6:Azamat
all34)%(*)#:DG:Ko_=ddhaogj;ldg
#year=4:2016
#dkgjdlkdag:dfgdfgd
some other text
"""
Dict{String,String} with 3 entries:
"name" => "Azamat"
"string" => "some text\ndgdfg:dgdf=ert\n#name=6:Azamat\nall34)%(*)#:DG:Ko_=ddhaogj;ldg\n#year=4:2016\n#dkgjdlkdag:dfgdfgd\nsome other text\n"
"year" => "2016"
julia>
seems like a job for regex:
julia> string_with_attributes = """
some text
dgdfg:dgdf=ert
#name=6:Azamat
all34)%(*)#:DG:Ko_=ddhaogj;ldg
#year=4:2016
#dkgjdlkdag:dfgdfgd
some other text
"""
"some text\ndgdfg:dgdf=ert\n#name=6:Azamat\nall34)%(*)#:DG:Ko_=ddhaogj;ldg\n#year=4:2016\n#dkgjdlkdag:dfgdfgd\nsome other text\n"
julia> s = Dict()
Dict{Any,Any} with 0 entries
julia> for i in eachmatch(r"(?<=#)\b.*(?==).*(?=\n)", string_with_attributes)
push!(s, match(r".*(?==)", i.match).match => match(r"(?<=:).*", i.match).match)
end
julia> s
Dict{Any,Any} with 2 entries:
"name" => "Azamat"
"year" => "2016"
So, turns out what I needed was to extend the Base.getindex method from Indexing interface.
Here is the solution that I ended up doing:
julia>
function Base.getindex(object::S, attribute::AbstractString) where {S <: AbstractString}
m = match( Regex("#$(attribute)=(\\d*):(.*)\n"), object )
(typeof(m) == Void) && error("$(object) has no attribute with the name $(attribute)")
return m.captures[end]::SubString{S}
end
julia> string_with_attributes = """
some text
dgdfg:dgdf=ert
#name=6:Azamat
all34)%(*)#:DG:Ko_=ddhaogj;ldg
#year=4:2016
#dkgjdlkdag:dfgdfgd
some other text
"""
julia> string_with_attributes["name"]
"Azamat"
julia> string_with_attributes["year"]
"2016"

Julia: Best practice to unpack parameters inside a function

I can unpack a tuple. I'm trying to write a function (or macro) that would unpack a subset of these from an instance of the type-constructor Parameters(). That is, I know how to do:
a,b,c = unpack(p::Parameters)
But I would like to do something like this:
b,c = unpack(p::Parameters, b,c)
or maybe even lazier:
unpack(p::Parameters, b, c)
This is to avoid writing things like:
function unpack_all_oldstyle(p::Parameters)
a=p.a; b=p.b; c=p.c; ... z=p.z;
return a,b,c,...,z
end
There's something wrong with my approach, but hopefully there is a fix.
In case it wasn't clear from the wording of my question, I'm a total ignoramus. I read about unpacking the ellipsis here: how-to-pass-tuple-as-function-arguments
"module UP tests Unpacking Parameters"
module UP
struct Parameters
a::Int64
b::Int64
c::Int64
end
"this method sets default parameters and returns a tuple of default values"
function Parameters(;
a::Int64 = 3,
b::Int64 = 11,
c::Int64 = 101
)
Parameters(a, b, c)
end
"this function unpacks all parameters"
function unpack_all(p::Parameters)
return p.a, p.b, p.c
end
"this function tests the unpacking function: in the body of the function one can now refer to a rather than p.a : worth the effort if you have dozens of parameters and complicated expressions to compute, e.g. type (-b+sqrt(b^2-4*a*c))/2/a instead of (-p.b+sqrt(p.b^2-4*p.a *p.c))/2/p.a"
function unpack_all_test(p::Parameters)
a, b, c = unpack_all(p)
return a, b, c
end
"""
This function is intended to unpack selected parameters. The first, unnamed argument is the constructor for all parameters. The second argument is a tuple of selected parameters.
"""
function unpack_selected(p::Parameters; x...)
return p.x
end
function unpack_selected_test(p::Parameters; x...)
x = unpack_selected(p, x)
return x
end
export Parameters, unpack_all, unpack_all_test, unpack_selected, unpack_selected_test
end
p = UP.Parameters() # make an instance
UP.unpack_all_test(p)
## (3,11,101) ## Test successful
UP.unpack_selected_test(p, 12)
## 12 ## intended outcome
UP.unpack_selected_test(p, b)
## 11 ## intended outcome
UP.unpack_selected_test(p, c, b, a)
## (101,11,3) ## intended outcome
There already exists one: Parameters.jl.
julia> using Parameters
julia> struct Params
a::Int64
b::Int64
c::Int64
end
julia> #unpack a, c = Params(1,2,3)
Params(1,2,3)
julia> a,c
(1,3)
julia> #with_kw struct Params
a::Int64 = 3
b::Int64 = 11
c::Int64 = 101
end
julia> #unpack c,b,a = Params()
Params
a: Int64 3
b: Int64 11
c: Int64 101
julia> c,b,a
(101,11,3)
BTW, you can fix your unpack_selected by:
unpack_selected(p::Parameters, fields...) = map(x->getfield(p, x), fields).
# note that, the selected field names should be Symbol here
julia> unpack_selected(p, :b)
(11,)
julia> unpack_selected(p, :c, :b, :a)
(101,11,3)

Resources