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, tpl) 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 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