Easier way to read input from a file - julia

I need to read input from the following input file and initialise all the variables.
Input File
A=1.0
B=1.0
C=2.0
I use following Julia code to read this.
# Read the delemited file
in = readdlm("inputFile.in",'=');
# Declare all the variables before initialising them with the data from input file.
A=0.0; B=0.0; C=0.0;
# Parsing
for i in 1:length(in[:,1])
if in[i,1] == "A"
A=in[i,2]
elseif in[i,1] == "B"
B=in[i,2]
elseif in[i,1] == "C"
C=in[i,2]
else
println(STDERR,in[i,1],"\tKeyword not recognised.")
exit()
end
end
This method is not scalable to large number of input variables. As you will notice, I want to read the variable names and initialise them to the value given in the input file.
Is there a more elegant/short way of doing this? I want to save the names of the variables in an array and use a for loop to read them from the file.
Thank you for your help.

Maybe like this?
Basic approach
I'm going to read values from file config.txt which contains the following
A=1.0
B = 2.1
C= 3.3
D =4.4
I do not want to hardcode what variables could be there, so I'm going to keep all of them in one Dict, like this:
julia> vars = Dict{String, Float64}()
Dict{String,Float64} with 0 entries
julia> f = open("config.txt")
IOStream(<file config.txt>)
julia> for line in eachline(f)
var, val = split(line, "=")
vars[strip(var)] = parse(Float64, val)
end
julia> vars
Dict{String,Float64} with 4 entries:
"B" => 2.1
"A" => 1.0
"C" => 3.3
"D" => 4.4
julia> vars["A"]
1.0
Reading only some variables
If you want to limit the set of variables which should be read, it's easy to do as well:
julia> vars = Dict{String, Float64}()
Dict{String,Float64} with 0 entries
julia> allowed = ["A", "B", "C"]
3-element Array{String,1}:
"A"
"B"
"C"
julia> f = open("config.txt")
IOStream(<file config.txt>)
julia> for line in eachline(f)
var, val = split(line, "=")
stripped = strip(var)
if stripped in allowed
vars[stripped] = parse(Float64, val)
end
end
julia> vars
Dict{String,Float64} with 3 entries:
"B" => 2.1
"A" => 1.0
"C" => 3.3
Now D=... from config.txt is ignored, as the name was not in allowed.
Having variables as variables, not as Dict
One more approach would be:
function go(;A=0.0, B=0.0, C=0.0)
println("A = $A, B = $B, C = $C")
end
vars = Dict{Symbol, Float64}()
f = open("config.txt")
allowed = ["A", "B", "C"]
for line in eachline(f)
var, val = split(line, "=")
stripped = strip(var)
if stripped in allowed
vars[Symbol(stripped)] = parse(Float64, val)
end
end
go(;vars...)
Running this with the same config.txt prints
A = 1.0, B = 2.1, C = 3.3

If you want to have your variables in a text file in the format you have them then this will work nicely (it just parse/eval's each line).
inputfile = readlines("inputFile.in")
eval.(parse.(inputfile))
I just realised this doesn't use a for loop, is that a requirement? if so then something like this would also be good:
open("inputFile.in", "r") do f
for line in eachline(f)
eval(parse(line))
end
end
But if you don't need to save your variables in a text file then the JLD package is the most convenient option & will be much more scale-able.
using JLD
A=1.0
B=1.0
C=2.0
#save "myfirstsave.jld" A B C
#load "myfirstsave.jld"

If the input file contains Julia code only, you can just include it:
include("inputFile.in")
println("A", A)
Depending on your workflow, it may be easier than using JLD, since your input file remains a single human-readable text file, rather than a binary file generated by a another text file.
The main con is that you cannot refer to the set of input variables programmatically, e.g. list them, check for existence, etc...

Related

How do I turn a string into a specific enum type in a macro?

I have a module with an enum defined in it.
module myModule
#enum type A B B C D
end
type1 = myModule.A
Now I want to declare an instance of this enum type but I only have a string specifying which type it is. I tried the following:
str = "B"
type2 = eval(:(myModule.Symbol($str)))
But I get a warning message which I do not quite understand:
WARNING: replacing module myModule.
and the type of type2 is also just a Symbol.
Probably the simplest way is to use getproperty:
julia> module myModule
#enum type A B C D
end
Main.myModule
julia> str = "B";
julia> getproperty(myModule, Symbol(str))
B::type = 1
Alternatively, you could create your expression as a string and then parse and evaluate it:
julia> eval(Meta.parse(string("myModule.", str)))
B::type = 1
Or, the same thing, but with string interpolation instead of using the string function:
julia> eval(Meta.parse("myModule.$str"))
B::type = 1
Note that the syntax myModule.Symbol(str) is not equivalent to myModule.B. It looks like that syntax really just calls Symbol(str) in the global scope. For example, try the following:
julia> myModule.length([1, 2, 3])
3
julia> #code_lowered myModule.length([1, 2, 3])
CodeInfo(
1 ─ %1 = (Base.arraylen)(a)
└── return %1
)

How to use haskey() and in() functions with complex dictionnary keys in Julia?

haskey() and in() functions are very useful to test the content of dictionaries in Julia :
julia> dict = Dict("a" => 1, "b" => 2, "c" => 3, "d" => 4, "e" => 5)
Dict{String,Int64} with 5 entries:
"c" => 3
"e" => 5
"b" => 2
"a" => 1
"d" => 4
julia> haskey(dict, "a")
true
julia> in(("a" => 1), dict)
true
but I was surprised by their behavior with complex keys :
julia> immutable MyT
A::String
B::Int64
end
julia> a = Dict(MyT("Tom",191)=>1,MyT("Bob",20)=>1,MyT("Jo",315)=>1,MyT("Luc",493)=>1)
Dict{MyT,Int64} with 4 entries:
MyT("Tom",191) => 1
MyT("Jo",315) => 1
MyT("Bob",20) => 1
MyT("Luc",493) => 1
julia> keys(a)
Base.KeyIterator for a Dict{MyT,Int64} with 4 entries. Keys:
MyT("Tom",191)
MyT("Jo",315)
MyT("Bob",20)
MyT("Luc",493)
julia> haskey(a, MyT("Tom",191))
false
julia> in((MyT("Tom",191) => 1), a)
false
What I did wrong ?
Thank you very much for your comments !
Thanks to #Michael K. Borregaard, I can propose this solution :
a = Dict{MyT, Int64}()
keyArray = Array{MyT,1}()
keyArray = [MyT("Tom",191),MyT("Bob",20),MyT("Jo",315),MyT("Luc",493)]
for i in keyArray
a[i] = 1
end
println(a)
# Dict(MyT("Tom",191)=>1,MyT("Tom",191)=>1,MyT("Luc",493)=>1,MyT("Jo",315)=>1,MyT("Luc",493)=>1,MyT("Bob",20)=>1,MyT("Jo",315)=>1,MyT("Bob",20)=>1)
keyArray[1] # MyT("Tom",191)
haskey(a, keyArray[1]) # true
But I have to store keys in a separate array. This means that can't warranty the unicity of the keys which is the strength of the dictionaries and why I choose to use it :(
So I have to use another step :
unique(keyArray)
Another better solution :
function CompareKeys(k1::MyT, k2::MyT)
if k1.A == k2.A && k1.B == k2.B
return true
else
return false
end
end
function ExistKey(k::MyT, d::Dict{MyT, Int64})
for i in keys(d)
if CompareKeys(k, i)
return true
end
end
return false
end
a = Dict(MyT("Tom",191)=>1,MyT("Bob",20)=>1,MyT("Jo",315)=>1,MyT("Luc",493)=>1)
ExistKey(MyT("Tom",192),a) # false
ExistKey(MyT("Tom",191),a) # true
Compared to Julia, Go is more straightforward for this problem :
package main
import (
"fmt"
)
type MyT struct {
A string
B int
}
func main() {
dic := map[MyT]int{MyT{"Bob", 10}: 1, MyT{"Jo", 21}: 1}
if _, ok := dic[MyT{"Bob", 10}]; ok {
fmt.Println("key exists")
}
}
// answer is "key exists"
You just need to teach your MyT type that you want it to consider equality in terms of its composite fields:
julia> immutable MyT
A::String
B::Int64
end
import Base: ==, hash
==(x::MyT, y::MyT) = x.A == y.A && x.B == y.B
hash(x::MyT, h::UInt) = hash(x.A, hash(x.B, hash(0x7d6979235cb005d0, h)))
julia> a = Dict(MyT("Tom",191)=>1,MyT("Bob",20)=>1,MyT("Jo",315)=>1,MyT("Luc",493)=>1)
Dict{MyT,Int64} with 4 entries:
MyT("Jo", 315) => 1
MyT("Luc", 493) => 1
MyT("Tom", 191) => 1
MyT("Bob", 20) => 1
julia> haskey(a, MyT("Tom",191))
true
julia> in((MyT("Tom",191) => 1), a)
true
There are lots of good answers here, I'd just like to add a subtlety: this is partly because == calls === rather than recursively calling == when checking for structural equality, and partly because equal (==) strings are not generally identical (===) currently. Specifically, the fact that MyT("foo", 1) != MyT("foo", 1) is because "foo" !== "foo".
Strings are only "immutable by convention" – they are technically mutable, but Julia doesn't expose APIs for mutating them and encourages you not to mutate them. You can, however, access their underlying bytes and mutate that, which allows you to write a program that distinguishes two strings by getting by mutating one and not the other. That means that they cannot be === in the sense of Henry Baker's "EGAL" predicate (also here). If you have an immutable type with only "primitive" type fields, then this does not happen:
julia> immutable MyT2 # `struct MyT2` in 0.6
A::Float64
B::Int
end
julia> x = MyT2(1, 1)
MyT2(1.0, 1)
julia> y = MyT2(1, 1)
MyT2(1.0, 1)
julia> x == y
true
julia> x === y
true
I have already proposed that we change this and have == recursively call ==. This should be fixed, someone just needs to do the work. Moreover, in Julia 1.0 we could make Strings truly immutable rather than merely immutable by convention, and therefore have "foo" === "foo" be true. I've created an issue to discuss and track this change.
You're creating a new object in the haskey call. But two objects created by MyT("Tom", 191) are just two different MyT objects with the same field values.
Instead, do
key1 = MyT("Tom", 191)
a = Dict(key1 => 1)
haskey(a, key1)
see also
key2 = MyT("Tom", 191)
key1 == key2 # false
A julia-ideomatic way to deal with this would be to define an == method for MyT objects, so two objects are equal if they have the same field values. That would allow you to use them like you do.
It depends whether you need the type to be complex. Another easy and performant way to do what you want is to use a Tuple as the key:
a = Dict(("Tom", 191) => 1)
haskey(a, ("Tom", 191)) # true
a[("Tom", 191)] # 1
My approach would be similar to Matt's, but a bit simpler(?). Tuples are perfectly valid dictionary keys, so I would simply overload the relevant functions to convert your type back and forth to a tuple:
julia> immutable M; A::String; B::Int64; end
julia> import Base: =>, haskey, in
julia> =>(a::M, b) = (a.A, a.B)=>b
julia> haskey(a::Dict, b::M) = haskey(a, (b.A, b.B))
julia> in(a::Pair{M, Int64}, b::Int64) = in((a.first.A,a.first.B)=>a.second,b)
julia> a = Dict(M("Dick", 10)=>1, M("Harry", 20)=>2)
Dict{Tuple{String,Int64},Int64} with 2 entries:
("Dick", 10) => 1
("Harry", 20) => 2
julia> haskey(a, M("Dick", 10))
true
julia> in(M("Dick", 10)=>1, a)
true
"Compared to Julia, Go is more straightforward for this problem"
True. It also happens to be more error-prone (depending on your perspective). If you wanted to differentiate between two objects (used as keys) that do not correspond to the same object in memory, then Go's approach of simply testing 'value equality' would have landed you in trouble here (though one could argue 'value equality' generally makes more sense when comparing 'keys').

How to initialize a dictionary in Julia?

When I tried to do:
d = {1:2, 3:10, 6:300, 2:1, 4:5}
I get the error:
syntax: { } vector syntax is discontinued
How to initialize a dictionary in Julia?
The {} syntax has been deprecated in julia for a while now. The way to construct a dict now is:
Given a single iterable argument, constructs a Dict whose key-value pairs are taken from 2-tuples (key,value) generated by the argument.
julia> Dict([("A", 1), ("B", 2)])
Dict{String,Int64} with 2 entries:
"B" => 2
"A" => 1
Alternatively, a sequence of pair arguments may be passed.
julia> Dict("A"=>1, "B"=>2)
Dict{String,Int64} with 2 entries:
"B" => 2
"A" => 1
(as quoted from the documentation, which can be obtained by pressing ? in the terminal to access the "help" mode, and then type Dict)

Julia : construct Dictionary with tuple values

Is there a possibility to construct dictionary with tuple values in Julia?
I tried
dict = Dict{Int64, (Int64, Int64)}()
dict = Dict{Int64, Tuple(Int64, Int64)}()
I also tried inserting tuple values but I was able to change them after so they were not tuples.
Any idea?
Edit:
parallel_check = Dict{Any, (Any, Any)}()
for i in 1:10
dict[i] = (i+41, i+41)
end
dict[1][2] = 1 # not able to change this way, setindex error!
dict[1] = (3, 5) # this is acceptable. why?
The syntax for tuple types (i.e. the types of tuples) changed from (Int64,Int64) in version 0.3 and earlier to Tuple{Int64,Int64} in 0.4. Note the curly braces, not parens around Int64,Int64. You can also discover this at the REPL by applying the typeof function to an example tuple:
julia> typeof((1,2))
Tuple{Int64,Int64}
So you can construct the dictionary you want like this:
julia> dict = Dict{Int64,Tuple{Int64,Int64}}()
Dict{Int64,Tuple{Int64,Int64}} with 0 entries
julia> dict[1] = (2,3)
(2,3)
julia> dict[2.0] = (3.0,4)
(3.0,4)
julia> dict
Dict{Int64,Tuple{Int64,Int64}} with 2 entries:
2 => (3,4)
1 => (2,3)
The other part of your question is unrelated, but I'll answer it here anyway: tuples are immutable – you cannot change one of the elements in a tuple. Dictionaries, on the other hand are mutable, so you can assign an entirely new tuple value to a slot in a dictionary. In other words, when you write dict[1] = (3,5) you are assigning into dict, which is ok, but when you write dict[1][2] = 1 you are assigning into the tuple at position 1 in dict which is not ok.

Convert Dict to DataFrame in Julia

Suppose I have a Dict defined as follows:
x = Dict{AbstractString,Array{Integer,1}}("A" => [1,2,3], "B" => [4,5,6])
I want to convert this to a DataFrame object (from the DataFrames module). Constructing a DataFrame has a similar syntax to constructing a dictionary. For example, the above dictionary could be manually constructed as a data frame as follows:
DataFrame(A = [1,2,3], B = [4,5,6])
I haven't found a direct way to get from a dictionary to a data frame but I figured one could exploit the syntactic similarity and write a macro to do this. The following doesn't work at all but it illustrates the approach I had in mind:
macro dict_to_df(x)
typeof(eval(x)) <: Dict || throw(ArgumentError("Expected Dict"))
return quote
DataFrame(
for k in keys(eval(x))
#eval ($k) = $(eval(x)[$k])
end
)
end
end
I also tried writing this as a function, which does work when all dictionary values have the same length:
function dict_to_df(x::Dict)
s = "DataFrame("
for k in keys(x)
v = x[k]
if typeof(v) <: AbstractString
v = string('"', v, '"')
end
s *= "$(k) = $(v),"
end
s = chop(s) * ")"
return eval(parse(s))
end
Is there a better, faster, or more idiomatic approach to this?
Another method could be
DataFrame(Any[values(x)...],Symbol[map(symbol,keys(x))...])
It was a bit tricky to get the types in order to access the right constructor. To get a list of the constructors for DataFrames I used methods(DataFrame).
The DataFrame(a=[1,2,3]) way of creating a DataFrame uses keyword arguments. To use splatting (...) for keyword arguments the keys need to be symbols. In the example x has strings, but these can be converted to symbols. In code, this is:
DataFrame(;[Symbol(k)=>v for (k,v) in x]...)
Finally, things would be cleaner if x had originally been with symbols. Then the code would go:
x = Dict{Symbol,Array{Integer,1}}(:A => [1,2,3], :B => [4,5,6])
df = DataFrame(;x...)

Resources