Julia 1.1 Create a grid (array of points in a grid)

Viewed 2796

Using Julia 1.1, I want to create a grid of points based on a vector of ranges

When using this code, it gives me a list of such points

u = [[i j ] for i in -1:0.5:1, j in -1:0.5:1]
[u...]

However, I am unable to develop a more generic approach that would create such a vector of multidimensional points when given an array of ranges

For example, develop a createGrid function that would take a Vector of n ranges as argument and output a list of all the points.

createGrid([1.:0.5:0., 1.:0.5:0., 1.:0.5:0.])

that would output:

27-element Array{Array{Float64,2},1}:
 [-1.0 -1.0 -1.0]
 [-0.5 -1.0 -1.0]
 [0.0 -1.0 -1.0] 
 [-1.0 -0.5 -1.0]
 [-0.5 -0.5 -1.0]
 [0.0 -0.5 -1.0] 
 [-1.0 0.0 -1.0] 
 [-0.5 0.0 -1.0] 
 [0.0 0.0 -1.0]  
 [-1.0 -1.0 -0.5]
 [-0.5 -1.0 -0.5]
 [0.0 -1.0 -0.5] 
 [-1.0 -0.5 -0.5]
 ⋮               

Thank you for any suggestion

3 Answers

Take a look at Iterators.product. It doesn't create the Arrays, but creates an object you can iterate over to get each new element of the grid as a Tuple (which is actually usually what you want).

julia> p = Iterators.product(-1.:0.5:0., -1.:0.5:0., -1.:0.5:0.);
julia> println.(p);
(-1.0, -1.0, -1.0)
(-0.5, -1.0, -1.0)
(0.0, -1.0, -1.0)
(-1.0, -0.5, -1.0)
(-0.5, -0.5, -1.0)
(0.0, -0.5, -1.0)
(-1.0, 0.0, -1.0)
⋮  

I would use:

using GeometryTypes
grid(ranges::NTuple{N, <: AbstractRange}) where N = Point.(Iterators.product(ranges...))
p = grid((-1.:0.5:0.0, -1.:0.5:0.0))

By using an NTuple instead of a Vector of ranges, this methods becomes type stable (the return type gets inferred as e.g Vector{Point{2, Float64}}). Also, using Points is more efficient than Array{Array{Float64,1},1}, has C-compatible layout and has all the operations defined which you need for points... As a bonus, it directly plots in Makie / Plots as points :)

Just to add to the excellent answer above, if you do want a vector-of-vectors you can collect each of the tuples into a vector, and then call vec to flatten this array-of-vectors into a vector-of-vectors

julia> p = Iterators.product(-1.0:0.5:0.0, -1.0:0.5:0.0, -1.0:0.5:0.0);

julia> collect.(p)
3×3×3 Array{Array{Float64,1},3}:
[:, :, 1] =
 [-1.0, -1.0, -1.0]  [-1.0, -0.5, -1.0]  [-1.0, 0.0, -1.0]
 [-0.5, -1.0, -1.0]  [-0.5, -0.5, -1.0]  [-0.5, 0.0, -1.0]
 [0.0, -1.0, -1.0]   [0.0, -0.5, -1.0]   [0.0, 0.0, -1.0]

[:, :, 2] =
 [-1.0, -1.0, -0.5]  [-1.0, -0.5, -0.5]  [-1.0, 0.0, -0.5]
 [-0.5, -1.0, -0.5]  [-0.5, -0.5, -0.5]  [-0.5, 0.0, -0.5]
 [0.0, -1.0, -0.5]   [0.0, -0.5, -0.5]   [0.0, 0.0, -0.5]

[:, :, 3] =
 [-1.0, -1.0, 0.0]  [-1.0, -0.5, 0.0]  [-1.0, 0.0, 0.0]
 [-0.5, -1.0, 0.0]  [-0.5, -0.5, 0.0]  [-0.5, 0.0, 0.0]
 [0.0, -1.0, 0.0]   [0.0, -0.5, 0.0]   [0.0, 0.0, 0.0]

julia> vec(collect.(p))
27-element Array{Array{Float64,1},1}:
 [-1.0, -1.0, -1.0]
 [-0.5, -1.0, -1.0]
 [0.0, -1.0, -1.0]
 [-1.0, -0.5, -1.0]
 [-0.5, -0.5, -1.0]
 [0.0, -0.5, -1.0]
 [-1.0, 0.0, -1.0]
 ⋮
Related