Create grid coordinates in Julia

In Julia, what's the best way to make an array (X, Y) like this?

0 0
1 0
2 0
3 0
0 1
1 1
2 1
3 1
0 2
1 2
2 2
3 2
0 3
1 3
2 3
3 3

      

Coordinates are regular and straightforward, but not necessarily integers.

+3


source to share


3 answers


Julia 0.6 includes an efficient iterator product

that allows for a fourth solution. Comparison of all solutions:

using Base.Iterators

f1(xs, ys) = [[xs[i] for i in 1:length(xs), j in 1:length(ys)][:] [ys[j] for i in 1:length(xs), j in 1:length(ys)][:]]
f2(xs, ys) = hcat(repeat(xs, outer=length(ys)), repeat(ys, inner=length(xs)))
f3(xs, ys) = vcat(([x y] for y in ys for x in xs)...)
f4(xs, ys) = (eltype(xs) == eltype(ys) || error("eltypes must match"); 
                reinterpret(eltype(xs), collect(product(xs, ys)), (2, length(xs)*length(ys)))')

xs = 1:3
ys = 0:4

@show f1(xs, ys) == f2(xs, ys) == f3(xs, ys) == f4(xs, ys)

using BenchmarkTools

@btime f1($xs, $ys)
@btime f2($xs, $ys)
@btime f3($xs, $ys)
@btime f4($xs, $ys)

      

On my PC, this results in:

f1(xs, ys) == f2(xs, ys) == f3(xs, ys) == f4(xs, ys) = true
  548.508 ns (8 allocations: 1.23 KiB)
  3.792 ฮผs (49 allocations: 2.45 KiB)
  1.916 ฮผs (51 allocations: 3.17 KiB)
  353.880 ns (8 allocations: 912 bytes)

      

For xs = 1:300

and ys=0:400

we get:

f1(xs, ys) == f2(xs, ys) == f3(xs, ys) == f4(xs, ys) = true
  1.538 ms (13 allocations: 5.51 MiB)
  1.032 ms (1636 allocations: 3.72 MiB)
  16.668 ms (360924 allocations: 24.95 MiB)
  927.001 ฮผs (10 allocations: 3.67 MiB)

      

Edit:

Most likely the fastest method is to loop directly over the preallocated array:



function f5(xs, ys)
    lx, ly = length(xs), length(ys)
    res = Array{Base.promote_eltype(xs, ys), 2}(lx*ly, 2)
    ind = 1
    for y in ys, x in xs
        res[ind, 1] = x
        res[ind, 2] = y
        ind += 1
    end
    res
end

      

For xs = 1:3

and ys = 0:4

, f5

accepts 65.339 ns (1 allocation: 336 bytes)

.

For xs = 1:300

and ys = 0:400

required 280.852 ฮผs (2 allocations: 1.84 MiB)

.

Edit 2:

Incorporating f6

from Dan Getz's comment:

function f6(xs, ys)
    lx, ly = length(xs), length(ys)
    lxly = lx*ly
    res = Array{Base.promote_eltype(xs, ys), 2}(lxly, 2)
    ind = 1
    while ind<=lxly
        @inbounds for x in xs
            res[ind] = x
            ind += 1
        end
    end
    for y in ys
        @inbounds for i=1:lx
        res[ind] = y
        ind += 1
        end
    end
    res
end

      

Given the large column order of Julia arrays, it reduces the timings to 47.452 ns (1 allocation: 336 bytes)

and 171.709 ฮผs (2 allocations: 1.84 MiB)

accordingly.

+4


source


It looks like a trick. Not sure if this is the best solution. Seems a little confusing.



xs = 0:3;
ys = 0:3;
out = [[xs[i] for i in 1:length(xs), j in 1:length(ys)][:] [ys[j] for i in 1:length(xs), j in 1:length(ys)][:]]

      

+2


source


sounds like a job for repeat The : hcat(repeat(0:3, outer=4), repeat(0:3, inner=4))

.

Note that this is too slower than understanding an array when xs

or is ys

small (e.g. 3

, 30

).

+1


source







All Articles