I have two vectors, say, x=[1;1] and y=[2;2]
I want to construct a vector whose element is a combination of these two, i.e. z=[[1,2],[1,2]]
What is the most efficient way to do that?
Just use zip. By default, this will create a vector of tuples:
julia> z = collect(zip(x,y))
2-element Array{Tuple{Int64,Int64},1}:
(1,2)
(1,2)
Note that this is different than what you wanted, but it'll be much more efficient. If you really want an array of arrays, you can use a comprehension:
julia> [[a,b] for (a,b) in zip(x,y)]
2-element Array{Array{Int64,1},1}:
[1,2]
[1,2]
Related
I want to create a two dimensional array of 2D vectors (to represent a vector field).
My code is something like this
N=10
dx=1/(N-1)
dy=1/(N-1)
#initial data
U=fill(zeros(2), (N, N))
for i=1:1:N
for j=1:1:N
U[i,j][1]=(i-1)*dx
U[i,j][2]=(j-1)*dy
end
end
print(U[5, 7])
The result is [1.0, 1.0], which is not what I want. I have no idea why. However, if I change the code to something like this
N=10
dx=1/(N-1)
dy=1/(N-1)
#initial data
U=fill(zeros(2), (N, N))
for i=1:1:N
for j=1:1:N
U[i,j]=[(i-1)*dx, (i-1)*dx]
end
end
print(U[5, 7])
Then it print out the correct result, which is [0.4444444444444444, 0.6666666666666666]. So, what going on?
This behaviour is expected. Note the following:
julia> x = fill(zeros(1), 2)
2-element Array{Array{Float64,1},1}:
[0.0]
[0.0]
julia> x[1][1] = 5.0
5.0
julia> x[2][1]
5.0
I managed to change x[2][1] just by changing x[1][1]. You can probably guess the problem at this point. You are populating all the elements of your matrix with the same vector. Therefore when you mutate one, you are mutating all.
To get the behaviour you want, you could build your initial matrix like this:
x = [ zeros(2) for n in 1:N, m in 1:N ]
The key point here is to consider whether the first argument to your fill call is, or contains, a mutable. If it does not, then it'll work like you expected, e.g. fill(0.0, 2). But if it does contain a mutable, then the output of fill will contain pointers to the single mutable object, and you'll get the behaviour you've encountered above.
Note, my use of the word "contains" here is important, since an immutable that contains a mutable will still result in a pointer to the single mutable object and hence the behaviour you have encountered. So for example:
struct T1 ; x::Vector{Float64} ; end
T1() = T1(zeros(1))
x = fill(T1(), 2)
x[1].x[1] = 5.0
x[2].x[1]
still mutates the second element of x.
The issue is that fill(zeros(2), (N, N)) points to a single 2-element vector. So if you change the contents of one, they all change:
julia> U = fill(ones(2), 2)
2-element Vector{Vector{Float64}}:
[1.0, 1.0]
[1.0, 1.0]
julia> U[1][1] = 2
2
julia> U
2-element Vector{Vector{Float64}}:
[2.0, 1.0]
[2.0, 1.0]
Thus, in your first snippet, you only change the contents of the unique 2-element vector. Check your U, it should be filled with [1.0, 1.0].
In your second snippet however, you allocate new vectors in each entry of U, so you don't have this problem.
A solution is to preallocate differently. You could try, e.g.,
U = Array{Vector{Float64}}(undef, (N, N))
Given two vectors a = [1, 2] and b = [3, 4], how do I obtain the concatenated vector c = [1, 2, 3, 4]? It seems that hcat or vcat could be used as they work on arrays, but when using vectors to store collections of elements it seems unfitting to first think about the orientation of the data; it's just supposed to be a list of values.
You can write
[a; b]
Under the hood this is the same as vcat, but it's terser, looks better, and is easier to remember, as it's also consistent with literal matrix construction syntax.
An alternative for concatenating multiple vectors is
reduce(vcat, (a, b))
Most Array methods treat arrays as general "tensors" of arbitrary ranks ("data cubes"), so you do need to think about the orientation. In the general case, there's cat(a, b; dims), of which hcat and vcat are special cases.
There is another class of methods treating Vectors as list like. From those, append! is the method that, well, appends a vector to another. The problem is that it is mutable. So you can, for example, append!(copy(a), b), or use something like BangBang.NoBang.append (which just selects the right method internally, though).
For the case of more than two vectors to be concatenated, I like the pattern of
reduce(append!, (a, b), init=Int[])
I want to access the last element of some array.
I am using length:
last_element = x[length(x)]
Is this correct? Is there a canonical way to access the last element of an ordered collection in Julia?
length is fine if your array uses standard indexing. However, x[length(x)] will not necessarily return the last element if the array uses custom indexing.
A more general and explicit method is to use last, which will return the last element of an array regardless of indexing scheme:
julia> x = rand(3)
3-element Array{Float64,1}:
0.7633644675721114
0.396645489023141
0.4086436862248366
julia> last(x)
0.4086436862248366
If you need the index of the last element, use lastindex:
julia> lastindex(x)
3
The following three methods are equivalent:
julia> last(x)
0.4086436862248366
julia> x[lastindex(x)]
0.4086436862248366
julia> x[end]
0.4086436862248366
x[end] is syntax sugar for x[lastindex(x)].
I have defined two structs and a function like this
struct A
x::Float64
end
struct B
y::Float64
end
f(a::A, b::B) = a.x*sin(b.y)
f.([A(0.1), A(0.2)], [B(1.), B(2.), B(3.)])
But f returns this error:
DimensionMismatch("arrays could not be broadcast to a common size")
How can I solve this error? I expect an array with 6 elements as the function output.
The problem is that your first argument is a 2-element Vector, and a second argument is 3-element Vector.
If you e.g. make the first argument a 1x2 Matrix, then all works fine:
julia> f.([A(0.1) A(0.2)], [B(1.), B(2.), B(3.)])
3×2 Array{Float64,2}:
0.0841471 0.168294
0.0909297 0.181859
0.014112 0.028224
(note that the missing or 1-length dimensions get automatically broadcasted)
Note that you could also broadcast calls to A and B constructors:
f.(A.([0.1 0.2]), B.(1.:3.))
The arrays have to have compatible dimensions - either identical in size and shape (local operations), or they span a larger vector space where each has singleton dimensions where the others have non-singleton dimensions, e.g. as an operation on the dimensions, the .* operator will cause the mapping
(1 x 1 x n) .* (p x q x 1) => p x q x n
I'm trying to create an array of two arrays. However, a = [[1, 2], [3, 4]] doesn't do that, it actually concats the arrays. This is true in Julia: [[1, 2], [3, 4]] == [1, 2, 3, 4]. Any idea?
As a temporary workaround, I use push!(push!(Array{Int, 1}[], a), b).
If you want an array of arrays as opposed to a matrix (i.e. 2-dimensional Array):
a = Array[ [1,2], [3,4] ]
You can parameterize (specify the type of the elements) an Array literal by putting the type in front of the []. So here we are parameterizing the Array literal with the Array type. This changes the interpretation of brackets inside the literal declaration.
Sean Mackesey's answer will give you something of type Array{Array{T,N},1} (or Array{Array{Int64,N},1}, if you put the type in front of []). If you instead want something more strongly typed, for example a vector of vectors of Int (i.e. Array{Array{Int64,1},1}), use the following:
a = Vector{Int}[ [1,2], [3,4] ]
In Julia v0.5, the original syntax now produces the desired result:
julia> a = [[1, 2], [3, 4]]
2-element Array{Array{Int64,1},1}:
[1,2]
[3,4]
julia> VERSION
v"0.5.0"
For a general answer on constructing Arrays of type Array:
In Julia, you can have an Array that holds other Array type objects. Consider the following examples of initializing various types of Arrays:
A = Array{Float64}(10,10) # A single Array, dimensions 10 by 10, of Float64 type objects
B = Array{Array}(10,10,10) # A 10 by 10 by 10 Array. Each element is an Array of unspecified type and dimension.
C = Array{Array{Float64}}(10) ## A length 10, one-dimensional Array. Each element is an Array of Float64 type objects but unspecified dimensions
D = Array{Array{Float64, 2}}(10) ## A length 10, one-dimensional Array. Each element of is an 2 dimensional array of Float 64 objects
Consider for instance, the differences between C and D here:
julia> C[1] = rand(3)
3-element Array{Float64,1}:
0.604771
0.985604
0.166444
julia> D[1] = rand(3)
ERROR: MethodError:
rand(3) produces an object of type Array{Float64,1}. Since the only specification for the elements of C are that they be Arrays with elements of type Float64, this fits within the definition of C. But, for D we specified that the elements must be 2 dimensional Arrays. Thus, since rand(3) does not produce a 2 dimensional array, we cannot use it to assign a value to a specific element of D
Specify Specific Dimensions of Arrays within an Array
Although we can specify that an Array will hold elements which are of type Array, and we can specify that, e.g. those elements should be 2-dimensional Arrays, we cannot directly specify the dimenions of those elements. E.g. we can't directly specify that we want an Array holding 10 Arrays, each of which being 5,5. We can see this from the syntax for the Array() function used to construct an Array:
Array{T}(dims)
constructs an uninitialized dense array with element type T. dims may be a tuple or a series of integer arguments. The syntax Array(T, dims) is also available, but deprecated.
The type of an Array in Julia encompasses the number of the dimensions but not the size of those dimensions. Thus, there is no place in this syntax to specify the precise dimensions. Nevertheless, a similar effect could be achieved using an Array comprehension:
E = [Array{Float64}(5,5) for idx in 1:10]
For those wondering, in v0.7 this is rather similar:
Array{Array{Float64,1},2}(undef, 10,10) #creates a two-dimensional array, ten rows and ten columns where each element is an array of type Float64
Array{Array{Float64, 2},1}(undef,10) #creates a one-dimensional array of length ten, where each element is a two-dimensional array of type Float64
You probably want a matrix:
julia> a = [1 2; 3 4]
2x2 Int64 Array:
1 2
3 4
Maybe a tuple:
julia> a = ([1,2],[3,4,5])
([1,2],[3,4,5])
You can also do {[1,2], [3,4]} which creates an Array{Any,1} containing [1,2] and [3,4] instead of an Array{Array{T,N},1}.