Matlab equivalent to Apply in Mathematica - arrays

I'm looking for an equivalent in Matlab to do the same as Apply in Mathematica. There it works like this
fct=#1+#2^2+#3^3+#4^4&;
Apply[fct,{a,b,c,d}]=f[a,b,c,d]
In Matlab, it's easy with a cell like this
fct=#(x1,x2,x3,x4) x1+x2^2+x3^3+x4^4;
mycell={a,b,c,d};
fct(mycell{:})
because mycell{:}=a,b,c,d is a valid comma-separated list of arguments for fct (see here).
Now, I would like to do the same with an array, e.g. like this:
myarrray=[a,b,c,d];
fct(myarray(:))
but this doesn't work. Sadly, things like fct(num2cell(myarray){:}) don't work either.
The problem here is that I would like to use the function as a one-liner (the array already exists, it can be called by its name). The reason for this is that the function should be an element of a struct.
Of course, in reality, my function looks differently. Note that I'm not looking for arrayfun which maps a function over an array.
(side note: In Mathematica, I can even write Apply[#1+#2^2+#3^3+#4^4&,{a,,b,c,d}] and there is even an infix notation for Apply making it more concise.)

Related

Julia, use of map to run a function multiple times,

I have some code that runs fine and does what I want, although there may be a simpler more elegant solution, this works :
round(Int16, floor(rand(TruncatedNormal(150,20,50,250))))
However when I try to execute it multiple times, using map, it throws an error saying it doesn't like the Int16 specification, so this:
map(round(Int16, floor(rand(TruncatedNormal(150,20,50,250)))), 1:2)
throws this error
ERROR: MethodError: objects of type Int16 are not callable
I just want to run it twice (in this case) and sum the results. Why is it unhappy? Thx. J
The first argument to map is a function. So, with your code, Julia is trying to make a function call:
round(Int16, floor(rand(TruncatedNormal(150,20,50,250))))()
But the output of round(Int16, ...) isn't a function, it's a number, so you cannot call it. That's why the error says "objects of type Int16 are not callable." You could fix this by using an anonymous function:
map(() -> round(Int16, floor(rand(TruncatedNormal(150,20,50,250)))), 1:2)
But the "Julian" way to do this is to use a comprehension:
[round(Int16, floor(rand(TruncatedNormal(150,20,50,250)))) for _ in 1:2]
EDIT:
If you are going to sum the results, then you can use something that looks like a comprehension but is called a generator expression. This is basically everything above with the [ ] around the expression. A generator expression can be used directly in functions like sum or mean, etc.
sum(round(Int16, floor(rand(TruncatedNormal(150,20,50,250)))) for _ in 1:2)
The advantage to generator expressions is that they don't allocate the memory for the full array. So, if you did this 100 times and used the sum approach above, you wouldn't need to allocate space for 100 numbers.
This goes beyond the original question, but OP wanted to use the sum expression where the 2 in 1:2 is a 1-element vector. Of course, if the input is always a 1-element vector, then I recommend first(x) like the comments. But this is a nice opportunity to show the importance of breaking things down into functions frequently in Julia. For example, you could take the entire sum expression and define a function
generatenumbers(n::Integer) = sum(... for _ in 1:n)
where n is a scalar. Then if you have some odd array expression for n (1-element vector, many such ns in a multi-dim array, etc.), you can just do:
generatenumbers.(ns)
# will apply to each element and return same shape as ns
If the de-sugaring logic is more complex than applying element-wise, you can even define:
generatenumbers(ns::AbstractArray) = # ... something more complex
The point is to define an "atomic" function that expresses the statement or task you want clearly, then use dispatch to apply it to more complicated data-structures that appear in practical code. This is a common design pattern in Julia (not the only option, but an effective one).
Adding on the answer from #darsnack.
If you want to run it multiple times in order to keep the results (it wasn't clear from the question). Then you could also ask rand to produce a vector by doing the following (and also making the type conversion through the floor call).
Moving from:
map(round(Int16, floor(rand(TruncatedNormal(150,20,50,250)))), 1:2)
to:
floor.(Int16, rand(TruncatedNormal(150,20,50,250), 2))
The documentation is here.

Applying Julia function to nested array of arrays

Is there a simpler way to do apply a function in Julia to nested array than defining a new function? - e.g. for this simple example:
a = collect(1:10)
b = [ a*i for i in 100:100:400]
arraylog(x) = log.(x) ## Need to define an extra function to do the inner array?
arraylog.(b)
I would use a comprehension just like you used it to define b: [log.(x) for x in b].
The benefit of this approach is that such code should be easy to read later.
EDIT
Referring to the answer by Tasos actually a comprehension implicitly defines an anonymous function that is passed to Base.Generator. In this use case a comprehension and map should be largely equivalent.
I assumed that MR_MPI-BGC wanted to avoid defining an anonymous function.
If it were allowed one could also use a double broadcast like this:
(x->log.(x)).(b)
which is even shorer but I thought that it would not be very readable in comparison to a comprehension.
You could define it as a lambda instead.
Obviously the distinction may be moot, depending on how you're using this later in your code, but if all you want is to not waste a line in your code for the sake of conciseness, you could easily dump this inside a map statement, for instance:
map( x->log.(x), b )
or, if you prefer do syntax:
map(b) do x
log.(x)
end
PS. I'm not familiar with a syntax which allows the broadcasted version of a function to be plugged directly into map, but if one exists it would be even cleaner than a lambda here ... but alas 'map( log., b )' is not valid syntax.

Using jsonencode with length 1 array

When using the MATLAB jsonencode function it seems very difficult to convert size 1 arrays into the correct JSON format i.e. [value]. For example if I do:
jsonencode(struct('words', [string('hello'), string('bye')]))
Then this produces:
{"words":["hello","bye"]}
which is correct. If however I do:
jsonencode(struct('words', [string('hello')]))
Then it produces:
{"words":"hello"}
losing the square brackets, which it needs because it is in general an array. The same happens when using a cell rather than an array, although using a cell does work if it's not inside a struct.
Any idea how I can work around this issue?
It seems this can be solved by using a cell rather than an array and then not creating the struct inline. Like
s.words = {'hello'};
jsonencode(s)
Output:
{"words":["hello"]}
I presume when created inline the cell functionality of matlab is actually trying to make multiple structs rather than multiple strings. Note that this still won't work with arrays as matlab treats a size one array as a scalar.

How to check if Fortran array contains value?

I've seen this asked for other languages, but having just found out how nicely Fortran can handle arrays, I thought there might be an easy way to do this without loops.
Currently I'm searching over a 3D array looking at 'nearest neighbours' to see if they contain the letter 'n', and whenever it finds this value, I want it to perform some clusterLabel assignment (which isn't relevant for this question)
I wanted to use if(lastNeighArray.eq."n") then...<rest of code>
but for obvious reasons it doesn't like checking an array against a value. Neither does it like me using lastNeighArray(:), even though I'd like it to check each of the elements one at a time. where(lastNeighArray.eq."n") doesn't work as I have a case statement inside the where loop and I get the error WHERE statements and constructs must not be nested.
So I'm a little stuck. What I really want is something like when(lastNeighArray.eq."n") but that doesn't exist.
I've also looked at any and forall but they don't seem like the right choice.
ANY should actually be the right choice
if ( ANY( lastNeighArray=="n" ) ) then
there is also ALL if you wanted the whole array to contain that value.

Multidimensional array of gtkwidgets

Is it possible to create a multidimensional array of gtkwidgets? Specifically something like this:
mywidgetlist[2]["title"];
Or should I be doing this in a different way? How would I do this?
Basically I have a number of "widgets" (Loaded from gtkbuilder) composed of smaller widgets and I want to be able to change certain values, so this array setup seems preferable.
Is there another way of doing this (Other than actually coding a complete widget using signals etc and placing them in a simple array?)
In C, you cannot use a string to index into an array. Or, strictly speaking you can, but it's almost never what you want to do.
For C solution using glib (handy if you already use GTK+), consider a single-dimensional array of GHashTable pointers.

Resources