I have the following variables
a1 = 2
a2 = 20
a3 = 200
Is it possible to output them while looping over the integers 1, 2 and 3? Something like the following although it doesn't work as intended
for i in [1,2,3]
println(:"a$i") # doesn't work
println("a" * string(i)) # doesn't work
end
You can use a dictionary, but this looks like a job for arrays:
julia> a = [2, 20, 200]
3-element Vector{Int64}:
2
20
200
julia> for i in eachindex(a)
println(a[i])
end
2
20
200
It is typical for beginner programmers to try to create and access variables dynamically. It is possible to do, but you should not do it. It makes code fragile and hard to read, and also slow and bug-prone. This is why data structures exist, that allow you to collect data in a structured way.
And alternative to arrays, is to use a tuple, a = (2, 20, 200). It works much the same way, except you cannot change a tuple after it has been created.
You could use a dictionary to store the variables:
julia> d = Dict("a1"=>2, "a2"=>20, "a3"=>200)
Dict{String, Int64} with 3 entries:
"a3" => 200
"a2" => 20
"a1" => 2
julia> for i in [1, 2, 3]
println(d["a$i"])
end
2
20
200
Related
I have an array a = [1, 2, 3, 4];. I want to compare each element of array a with a number and return a new array contains True/False elements in Julia as few steps as possible. I try result = a < 2 and expected array is result = [True, False, False, False] but it's not working. Hope your help
You need to vectorize (broadcast) the comparison operator so it operates on Vectors.
You can do this by adding a dot . to your code.
julia> a = [1, 2, 3, 4]
4-element Vector{Int64}:
1
2
3
4
julia> a .<= 2
4-element BitVector:
1
1
0
0
Read more about broadcasting here.
Note that Python's numpy will do this for you automatically, but there are cases where an operation might be ambiguous - do you want it to be element wise or a matrix multiplication? So Julia solves this by explicitly broadcasting any operation with the . command.
I would like to broadcast an operation to all values of a dictionary. For an array, I know I can broadcast an element-wise operation using:
julia> b1 = [1, 2, 3]
julia> b1./2
3-element Array{Float64,1}:
0.5
1.0
1.5
What is an efficient way of broadcasting the same operation to all values of a dictionary? Say, for the dictionary
a1 = Dict("A"=>1, "B"=>2)
An iteration protocol is defined for both keys and values of dictionaries, so you can just do, eg:
julia> d = Dict("a"=>1, "b"=>2)
Dict{String,Int64} with 2 entries:
"b" => 2
"a" => 1
julia> values(d).^2
2-element Array{Int64,1}:
4
1
If you want to alter the dictionary in-place, use map!, eg:
julia> map!(x->x^2, values(d))
Base.ValueIterator for a Dict{String,Int64} with 2 entries. Values:
4
1
julia> d
Dict{String,Int64} with 2 entries:
"b" => 4
"a" => 1
However, your function must output a type that can be converted back to the dictionary value type. In my example, I'm squaring Int which yields Int. However, in the question you are dividing by 2, which obviously yields Float64. If the float cannot be converted back to an integer, then you'll get an error.
Note, you can broadcast over keys also, e.g.:
julia> f(x) = "hello mr $(x)"
f (generic function with 1 method)
julia> f.(keys(d))
2-element Array{String,1}:
"hello mr b"
"hello mr a"
but this can not be done in-place, i.e. you can't use map! on keys.
Importantly, note that you should not instantiate the collection. Indeed, this would be inefficient. So avoid constructs like: collect(values(d)) ./ 2.
I see this Stackoverflow code for =>, but when I search Julia 1.0.0 on-line help for "=>", I get zero hits.
replace!(x, 0=>4) # The last expression is the focus of this question.
In the REPL help I get:
help?> =>
search: =>
Pair(x, y)
x => y
Construct a Pair object with type Pair{typeof(x), typeof(y)}. The elements are stored in the fields first and second.
They can also be accessed via iteration.
See also: Dict
Examples
≡≡≡≡≡≡≡≡≡≡
julia> p = "foo" => 7
"foo" => 7
julia> typeof(p)
Pair{String,Int64}
julia> p.first
"foo"
julia> for x in p
println(x)
end
foo
7
What does => do in replace!(x, 0=>4)? Does it create a pair, a replacement of all zeros by fours, or what? Why do I seem to not find it in the Julia 1.0.0 on-line docs?
EDIT
Code added to help me understand #Bill's helpful answer below:
julia> x = [1, 0, 3, 2, 0]
5-element Array{Int64,1}:
1
0
3
2
0
julia> replace!(x, 0=>4)
5-element Array{Int64,1}:
1
4
3
2
4
Edit 2
Besides #Bill's accepted answer, I found #Steven's answer helpful as well. Sorry I could not check them both, but Bill's came in first and they both offered useful information.
"What does => do in replace!(x, 0=>4)? Does it create a pair, a replacement of all zeros by fours, or what?"
It creates a Pair. In the function replace, a Pair in the second argument position means the multiple dispatch of replace() chooses a version of the replace function where, given a numeric array or string x, all items within x fitting the first part of the Pair are replaced with an instance of the second part of the Pair.
You can check the REPL docs for replace for details.
This small example should show how "=>" makes a pair
julia> replace("julia", Pair("u", "o"))
"jolia"
julia> replace("julia", "u" => "o")
"jolia"
"=>" operator means "Change into"
so
julia> replace("hello world",'l' => 'z')
"hezzo worzd"
means Change the string "hello world" using "change" 'l' "into" 'z'
and producing the resultant string "hezzo worzd"
julia> replace( [1,2,3,4,5], 3 => 666 )
5-element Array{Int64,1}:
1
2
666
4
5
Given an array as follows:
A = Array{Array{Int}}(2,2)
A[1,1] = [1,2]
A[1,2] = [3,4]
A[2,1] = [5,6]
A[2,2] = [7,8]
We then have that A is a 2x2 array with elements of type Array{Int}:
2×2 Array{Array{Int64,N} where N,2}:
[1, 2] [3, 4]
[5, 6] [7, 8]
It is possible to access the entries with e.g. A[1,2] but A[1,2,2] would not work since the third dimension is not present in A. However, A[1,2][2] works, since A[1,2] returns an array of length 2.
The question is then, what is a nice way to convert A into a 3-dimensional array, B, so that B[i,j,k] refers the the i,j-th array and the k-th element in that array. E.g. B[2,1,2] = 6.
There is a straightforward way to do this using 3 nested loops and reconstructing the array, element-by-element, but I'm hoping there is a nicer construction. (Some application of cat perhaps?)
You can construct a 3-d array from A using an array comprehension
julia> B = [ A[i,j][k] for i=1:2, j=:1:2, k=1:2 ]
2×2×2 Array{Int64,3}:
[:, :, 1] =
1 3
5 7
[:, :, 2] =
2 4
6 8
julia> B[2,1,2]
6
However a more general solution would be to overload the getindex function for arrays with the same type of A. This is more efficient since there is no need to copy the original data.
julia> import Base.getindex
julia> getindex(A::Array{Array{Int}}, i::Int, j::Int, k::Int) = A[i,j][k]
getindex (generic function with 179 methods)
julia> A[2,1,2]
6
With thanks to Dan Getz's comments, I think the following works well and is succinct:
cat(3,(getindex.(A,i) for i=1:2)...)
where 2 is the length of the nested array. It would also work for higher dimensions.
permutedims(reshape(collect(Base.Iterators.flatten(A)), (2,2,2)), (2,3,1))
also does the job and appears to be faster than the accepted cat() answer for me.
EDIT: I'm sorry, I just saw that this has already been suggested in the comments.
I know there is a function that does this, for example:
A = [1,2,0,0,4,0]
find(A)
3-element Array{Int64,1}:
1
2
5
I am trying to do it on my own way, however, I am stuck here
for i=1:endof(A)
if A[i] != 0
[]
end
end
Thanks in advance.
Here's one alternative:
function myfind(c)
a = similar(c, Int)
count = 1
#inbounds for i in eachindex(c)
a[count] = i
count += (c[i] != zero(eltype(c)))
end
return resize!(a, count-1)
end
It actually outperformed find for all the cases I tested, though for the very small example vector you posted, the difference was negligible. There is perhaps some performance advantage to avoiding the branch and dynamically growing the index array.
I have notice that the question is really confusion (because is poorly formulated, sorry about that). Therefore, there are two possible answers: one is [1,2,4]which is an array with the non-zero elements; the other is [1,2,5] which is an array of the indices of the non-zero elements.
Let´s begin with the first option
A = [1,2,0,0,4,0]
B = []
for i=1:endof(A)
if A[i] != 0
push!(B,i)
end
end
println(B)
The output is Any[1,2,5]
However, the type is not the one I wanted. Using typeof(B) it shows Array{Any,1} so I added this code:
B = Array{Int64}(B)
println(B)
typeof(B)
And the result is the desired
[1,2,5]
Array{Int64,1}
To improve its efficiency, following with the recommendations in the comments, I have specified the type of B with the eltype() function before the loop as follows:
A1 = [1,2,0,0,4,0] #The default type is Array{Int64,1}
B1 = eltype(A1)[] #Define the type of the 0 element array B with the type of A
#B1 = eltype(typeof(A))[] this is also valid
for i=1:endof(A1)
if A1[i] != 0
push!(B1::Array{Int64,1},i::Int64)
end
end
println(B1)
typeof(B1)
Then, the output is again the desired
[1,2,5]
Array{Int64,1}
The simplest way of doing this is using the function find(). However, since I´m a beginner, I wanted to do it in another way. However, there is another alternative provided by #DNF that outperform find() for the cases he has tested it (see below answers).
The second option, which creates an output matrix with the non-zero elements has been provided by other users (#Harrison Grodin and #P i) in this discussion.
Thanks all of you for the help!
You have a few options here.
Using the strategy you started with, you can use push! inside the for loop.
julia> B = Int[]
0-element Array{Int64,1}
julia> for element = A
if element != 0
push!(B, element)
end
end
julia> B
3-element Array{Int64,1}:
1
2
4
You can also opt to use short-circuit evaluation.
julia> for element = A
element != 0 && push!(B, element)
end
julia> for element = A
element == 0 || push!(B, element)
end
Both filter and list comprehensions are valid, as well!
julia> B = [element for element = A if element != 0]
3-element Array{Int64,1}:
1
2
4
julia> filter(n -> n != 0, A)
3-element Array{Int64,1}:
1
2
4
Edit: Thanks to the OP's comment, I have realized that the desired result is the indices of the nonzero elements, not the elements themselves. This can be achieved simply with the following. :)
julia> find(A)
3-element Array{Int64,1}:
1
2
5
Just because I don't see a simple solution posted here, this is approach I took to the same problem. I think it is the simplest and most elegant solution. Hope this closes the thread!
julia> A = [1,2,0,0,4,0];
julia> findall(!iszero,A)
3-element Vector{Int64}:
1
2
5