Getting the shape of nested arrays in Julia - julia

I am wondering whether there is a function that would compute the shape of nested arrays.
multiArr = [[1,2,3,4],[5,6,7,8]]
size(multiArr)
#Out > (2,)
I am looking for the output (2,4)
I am aware that if you convert it to a matrix you could get this output,
mat = reshape(hcat(multiArr...),size(multiArr)[1],size(multiArr[1])[1])
size(mat)
#Out > (2,4)
But wondering if there is a way to get the inner dimensions of nested arrays ?

You can just broadcast size over inner arrays:
julia> size.(multiArr)
2-element Vector{Tuple{Int64}}:
(4,)
(4,)
You will get a Vector of sizes because of course each of those can be different.

Related

How to define non-1 or arbitrary index array in Julia?

I know in Julia, the index of an array begin from 1. Like
b = Array{Float64, 1}(undef, 10)
This array b is a 1d array with 10 elements. The index of b begins from 1.
But, I want an array whose index is from 0 or any integer, how to do that in Julia?
Say, I want the index ranges from 0 to 9, and I tried to do things like
b = Array{Float64, 1}(undef, 0:9)
But obviously it does not work in Julia.
Can Julia easily define an array with arbitrary index range like Fortran?
I googled a little and it seems not easy to do this in Julia, am I missing something?
Is there a generic way in Julia to define arbitrary indexed array? Or do I have to install packages like OffsetArrays?
It seems just not so great that Julia cannot generically define arbitrary indexed array.
Thanks!
In Julia, this is provided by the OffsetArrays package. Try, for example
using OffsetArrays
A = rand(10)
OA = OffsetArray(A, 0:9)
OA[0]
then
julia> OA[0]
0.26079620656304203

Cumulative Integration Options With Julia

I have two 1-D arrays in which I would like to calculate the approximate cumulative integral of 1 array with respect to the scalar spacing specified by the 2nd array. MATLAB has a function called cumtrapz that handles this scenario. Is there something similar that I can try within Julia to accomplish the same thing?
The expected result is another 1-D array with the integral calculated for each element.
There is a numerical integration package for Julia (see the link) that defines cumul_integrate(X, Y) and uses the trapezoidal rule by default.
If this package didn't exist, though, you could easily write the function yourself and have a very efficient implementation out of the box because the loop does not come with a performance penalty.
Edit: Added an #assert to check matching vector dimensions and fixed a typo.
function cumtrapz(X::T, Y::T) where {T <: AbstractVector}
# Check matching vector length
#assert length(X) == length(Y)
# Initialize Output
out = similar(X)
out[1] = 0
# Iterate over arrays
for i in 2:length(X)
out[i] = out[i-1] + 0.5*(X[i] - X[i-1])*(Y[i] + Y[i-1])
end
# Return output
out
end

The use of map when the function that map is used on has arrays of inputs

Julia's "higher-order" function "map" looks very useful. But while it is easy to understand how it can be used on functions that have one input, it is not obvious how map can be used when the function has multiple inputs, and when each these may be arrays. I would like discover how map is used in that situation.
Suppose I have the following function:
function randomSample(items, weights)
sample(items, Weights(weights))
end
Example:
Pkg.add("StatsBase")
using StatsBase
randomSample([1,0],[0.5, 0.5])
How can map be used here? I have tried something like:
items = [1 0;1 0;1 0]
weights = [1 0;0.5 0.5;0.75 0.25]
map(randomSample(items,weights))
In the example above, I would expect Julia to output a 3 by 1 array of integers (from the items), each row being either 0 or 1 depending on the corresponding weights.
In your case when items and weights are Matrix you can use the eachrow function like this:
map(randomSample, eachrow(items), eachrow(weights))
If you are on Julia version earlier than 1.1 you can write:
map(i -> randomSample(items[i, :], weights[i, :]), axes(items, 1))
or
map(i -> randomSample(view(items,i, :), view(weights, i, :)), axes(items, 1))
(the latter avoids allocations)
However, in practice I would probably define items and weights as vectors of vectors:
items = [[1, 0],[1, 0],[1, 0]]
weights = [[1, 0], [0.5, 0.5], [0.75, 0.25]]
and then you can simply write:
map(randomSample, items, weights)
or
randomSample.(items, weights)
The reason for my preference is the following:
it is conceptually clearer what is the structure of your data
vector of vectors is easier to mutate (e.g. you can push! a new entry at the end)
vector of vectors can be ragged if needed
in some cases it might be a bit faster (iterating by rows in Julia is not optimal as it uses column-major indexing; of course you can fix it in your Matrix approach by assuming that you store your data columnwise not colwise as you currently do)
(this is not a very strong preference and you can probably choose whatever is more convenient to you)

How to know the index of the iterator when using map in Julia

I have an Array of arrays, called y:
y=Array(Vector{Int64}, 10)
which is basically a list of 1-dimensional arrays(10 of them), and each 1-dimensional array has length 5. Below is an example of how they are initialized:
for i in 1:10
y[i]=sample(1:20, 5)
end
Each 1-dimensional array includes 5 randomly sampled integers between 1 to 20.
Right now I am applying a map function where for each of those 1-dimensional arrays in y , excludes which numbers from 1 to 20:
map(x->setdiff(1:20, x), y)
However, I want to make sure when the function applied to y[i], if the output of setdiff(1:20, y[i]) includes i, i is excluded from the results. in other words I want a function that works like
setdiff(deleteat!(Vector(1:20),i) ,y[i])
but with map.
Mainly my question is that whether you can access the index in the map function.
P.S, I know how to do it with comprehensions, I wanted to know if it is possible to do it with map.
comprehension way:
[setdiff(deleteat!(Vector(1:20), index), value) for (index,value) in enumerate(y)]
Like this?
map(x -> setdiff(deleteat!(Vector(1:20), x[1]),x[2]), enumerate(y))
For your example gives this:
[2,3,4,5,7,8,9,10,11,12,13,15,17,19,20]
[1,3,5,6,7,8,9,10,11,13,16,17,18,20]
....
[1,2,4,7,8,10,11,12,13,14,15,16,17,18]
[1,2,3,5,6,8,11,12,13,14,15,16,17,19,20]

Initialize an array of arrays in Julia

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}.

Resources