I often need gridded versions of continuous functions. For a function with one argument, the usual broad cast is the most elegant way:
oned(x) = 2*x # 1D func
xs = 0.0:1.0:10.0 # x grid
oned_gridded = oned.(xs)
This method is often found in Julia examples.
Then, what about multiple-argument functions? You can of course use the list comprehension, but it’s a bit more verbose and a little bit more error-prone: [twod(x,y) for x in xs, y in ys]
.
I then found this thread
and came up with
twod(x,y) = "$(x) & $(y)" # 2D func
twod_tuple(tpl) = twod(tpl[1], tpl[2])
xs = 0.0:1.0:10.0 # x grid
ys = 20.0:3.0:50.0 # y grid
twod_gridded = twod_tuple.(Iterators.product(xs,ys))
Is this the most succinct solution today? Is there a standard way to convert a multiple-argument function into a single-tuple-argument function?
By the way, I’ve never been able to remember whether x in xs, y in ys
or y in ys, x in xs
is the correct order. That’s one of the reasons why I want to avoid the list comprehension to construct a multidimensional array. For the regular for
loop,
for j in axes(arr,2)
for i in axes(arr,1)
arr[i,j] = func_of(i,j)
is the right order because i
should change faster. The above is (functionally, at least) equivalent to
for j in axes(arr,2), i in axes(arr,1)
arr[i,j] = func_of(i,j)
So far so good. But then, you have to flip the order for the list comprehension
arr = [func_of(i,j) for i in is, j in js]
if I’m not mistaken.
In contrast, there is no such doubt in Iterator.product
because it is obviously the standard outer product in linear algebra.
For this reason, I’d probably abolish the regular for
loop from my code and write it this way:
for (i,j) in Iterators.product(is,js)
arr[i,j] = func_of(i,j)
After all, a nested for
loop is an outer product.
Then I hope the above loop can be written like
for (i,j) in is ⊗ js # outer product