Julia Array with different sized vectors - julia

When creating an array of various sized vectors(e.g. arrays) I am generating an error msg.
julia> A = [[1,2] [1,2,3] [1,4] [1] [1,5,6,7]]
ERROR: DimensionMismatch("vectors must have same lengths")
Stacktrace:
[1] hcat(::Array{Int64,1}, ::Array{Int64,1}, ::Array{Int64,1}, ::Vararg{Array{Int64,1},N} where N) at .\array.jl:1524
[2] top-level scope at none:0
Although, if I initalize an array and assign the vectors 'its okay'...
julia> A = Array{Any}(undef,5)
5-element Array{Any,1}:
#undef
#undef
#undef
#undef
#undef
pseudo code> A[i] = [x,y...]
2-element Array{Int64,1}:
1
2
julia> A
5-element Array{Any,1}:
[1, 2]
[1, 2, 3]
[1]
[1, 5]
[1, 2, 6, 4, 5]
Is there a way to initialize the array with the variously sized arrays or is Julia configured this way to prevent errors.

The space-separated syntax you're using for the outermost array is specifically for horizontal concatenation of matrices, so your code is trying to concatenate all of these vectors into a matrix, which doesn't work since they have different lengths. Use commas in the outer array like the inner one to get an array of arrays:
julia> A = [[1,2], [1,2,3], [1,4], [1], [1,5,6,7]]
5-element Array{Array{Int64,1},1}:
[1, 2]
[1, 2, 3]
[1, 4]
[1]
[1, 5, 6, 7]

Related

Julia pipe operator works with function involving multiplication but not with exponentiation

The following code works fine:
f(x) = 2*x
[1, 2, 3] |> f
However, the following code fails:
g(x) = x^2
[1, 2, 3] |> g
Closest candidates are:
^(::Union{AbstractChar, AbstractString}, ::Integer) at strings/basic.jl:718
^(::Complex{var"#s79"} where var"#s79"<:AbstractFloat, ::Integer) at complex.jl:818
^(::Complex{var"#s79"} where var"#s79"<:Integer, ::Integer) at complex.jl:820
...
Stacktrace:
[1] macro expansion
# ./none:0 [inlined]
[2] literal_pow
# ./none:0 [inlined]
[3] g(x::Vector{Int64})
# Main ./REPL[17]:1
[4] |>(x::Vector{Int64}, f::typeof(g))
# Base ./operators.jl:858
[5] top-level scope
This is not related to the pipe operator at all:
julia> [1, 2, 3] * 2
3-element Vector{Int64}:
2
4
6
julia> [1, 2, 3] ^ 2
ERROR: MethodError: no method matching ^(::Vector{Int64}, ::Int64)
If you want to apply an operation on every element in a container you should use broadcasting (see also https://julialang.org/blog/2017/01/moredots/)
julia> [1, 2, 3] .* 2
3-element Vector{Int64}:
2
4
6
julia> [1, 2, 3] .^ 2
3-element Vector{Int64}:
1
4
9
The fact that [1, 2, 3] * 2 works is because vector times scalar is a mathematical operation whereas vector raised to a scalar ([1, 2, 3] ^ 2) is not.
In addition to #fredrikekre 's answer, I would like to mention that the following works:
g(x) = x^2
[1, 2, 3] .|> g
Adding an extra dot for broadcasting does the trick and allows using the pipe operator thereby feeding collections to pipes and getting collections out.
Another way to get the broadcast operator have effect on the entire pipe is to use the #. macro:
f(x) = 2x
g(x) = x^2
#. [1, 2, 3] |> f |> g

How do you access multi-dimension array by N array of index element-wise?

Suppose we have
A = [1 2; 3 4]
In numpy, the following syntax will produce
A[[1,2],[1,2]] = [1,4]
But, in julia, the following produce a permutation which output
A[[1,2],[1,2]] = [1 2; 3 4]
Is there a concise way to achieve the same thing as numpy without using for loops?
To get what you want I would use CartesianIndex like this:
julia> A[CartesianIndex.([(1,1), (2,2)])]
2-element Vector{Int64}:
1
4
or
julia> A[[CartesianIndex(1,1), CartesianIndex(2,2)]]
2-element Vector{Int64}:
1
4
Like Bogumil said, you probably want to use CartesianIndex. But if you want to get your result from supplying the vectors of indices for each dimensions, as in your Python [1,2],[1,2] example, you need to zip these indices first:
julia> A[CartesianIndex.(zip([1,2], [1,2]))]
2-element Vector{Int64}:
1
4
How does this work? zip traverses both vectors of indices at the same time (like a zipper) and returns an iterator over the tuples of indices:
julia> zip([1,2],[1,2]) # is a lazy iterator
zip([1, 2], [1, 2])
julia> collect(zip([1,2],[1,2])) # collect to show all the tuples
2-element Vector{Tuple{Int64, Int64}}:
(1, 1)
(2, 2)
and then CartesianIndex turns them into cartesian indices, which can then be used to get the corresponding values in A:
julia> CartesianIndex.(zip([1,2],[1,2]))
2-element Vector{CartesianIndex{2}}:
CartesianIndex(1, 1)
CartesianIndex(2, 2)

How to initialise reduce and use accumulator in Julia

It works without initial value:
reduce(+, [2 3 4])
Tried multiple ways to provide initial value - nothing works
reduce(+, [2 3 4], 1)
reduce(+, 1, [2 3 4])
Also seems like reduce could be used only with 2 argument operator. What function should be used to reduce collection with custom functions that accept current value and accumulator? Something like code below?
reduce((accumulator, value) -> push!(accumulator, value^2), [1, 2, 3], [])
# => [1, 4, 9]
This example could be implemented as map(x -> x^2, [1, 2, 3]) but I would like to know how to implement it as reduce with accumulator.
julia version 1.1.1
The init argument to reduce is a keyword argument:
julia> reduce(+, [2 3 4], init = 1)
10
julia> reduce((accumulator, value) -> push!(accumulator, value^2), [1, 2, 3], init = [])
3-element Array{Any,1}:
1
4
9

Vectorized splatting

I'd like to be able to splat an array of tuples into a function in a vectorized fashion. For example, if I have the following function,
function foo(x, y)
x + y
end
and the following array of tuples,
args_array = [(1, 2), (3, 4), (5, 6)]
then I could use a list comprehension to obtain the desired result:
julia> [foo(args...) for args in args_array]
3-element Array{Int64,1}:
3
7
11
However, I would like to be able to use the dot vectorization notation for this operation:
julia> foo.(args_array...)
ERROR: MethodError: no method matching foo(::Int64, ::Int64, ::Int64)
But as you can see, that particular syntax doesn't work. Is there a vectorized way to do this?
foo.(args_array...) doesn't work because it's doing:
foo.((1, 2), (3, 4), (5, 6))
# which is roughly equivalent to
[foo(1,3,5), foo(2,4,6)]
In other words, it's taking each element of args_array as a separate argument and then broadcasting foo over those arguments. You want to broadcast foo over the elements directly. The trouble is that running:
foo.(args_array)
# is roughly equivalent to:
[foo((1,2)), foo((3,4)), foo((5,6))]
In other words, the broadcast syntax is just passing each tuple as a single argument to foo. We can fix that with a simple intermediate function:
julia> bar(args) = foo(args...);
julia> bar.(args_array)
3-element Array{Int64,1}:
3
7
11
Now that's doing what you want! You don't even need to construct the second argument if you don't want to. This is exactly equivalent:
julia> (args->foo(args...)).(args_array)
3-element Array{Int64,1}:
3
7
11
And in fact you can generalize this quite easily:
julia> splat(f) = args -> f(args...);
julia> (splat(foo)).(args_array)
3-element Array{Int64,1}:
3
7
11
You could zip the args_array, which effectively transposes the array of tuples:
julia> collect(zip(args_array...))
2-element Array{Tuple{Int64,Int64,Int64},1}:
(1, 3, 5)
(2, 4, 6)
Then you can broadcast foo over the transposed array (actually an iterator) of tuples:
julia> foo.(zip(args_array...)...)
(3, 7, 11)
However, this returns a tuple instead of an array. If you need the return value to be an array, you could use any of the following somewhat cryptic solutions:
julia> foo.(collect.(zip(args_array...))...)
3-element Array{Int64,1}:
3
7
11
julia> collect(foo.(zip(args_array...)...))
3-element Array{Int64,1}:
3
7
11
julia> [foo.(zip(args_array...)...)...]
3-element Array{Int64,1}:
3
7
11
How about
[foo(x,y) for (x,y) in args_array]

Circular permutations

Given a vector z = [1, 2, 3], I want to create a vector of vectors with all circular permutations of z (i.e. zp = [[1,2,3], [3,1,2], [2,3,1]]).
I can print all elements of zp with
for i in 1:length(z)
push!(z, shift!(z)) |> println
end
How can I store the resulting permutations? Note that
zp = Vector(length(z))
for i in 1:length(z)
push!(z, shift!(z))
push!(zp, z)
end
doesn't work as it stores the same vector z 3 times in zp.
One way would just be to copy the vector before pushing it:
z = [1, 2, 3];
zp = Vector();
for i in 1:length(z)
push!(z, shift!(z))
push!(zp, copy(z))
end
gives me
julia> zp
3-element Array{Any,1}:
[2,3,1]
[3,1,2]
[1,2,3]
But I tend to prefer avoiding mutating operations when I can. So I'd instead write this as
julia> zp = [circshift(z, i) for i=1:length(z)]
3-element Array{Array{Int64,1},1}:
[3,1,2]
[2,3,1]
[1,2,3]
This seems to execute pretty quick on my machine (faster than a comprehension):
julia> z=[1,2,3]
3-element Array{Int64,1}:
1
2
3
julia> zp=Vector{typeof(z)}(length(z))
3-element Array{Array{Int64,1},1}:
#undef
#undef
#undef
julia> for i=1:length(z)
zp[i]=circshift(z,i-1)
end
julia> zp
3-element Array{Array{Int64,1},1}:
[1,2,3]
[3,1,2]
[2,3,1]
julia>

Resources