What general tips do you have for golfing in Octave? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to Octave (e.g. "remove comments" is not an answer). Please post one tip per answer.
11 Answers
- Once you know, that
a
is free of zero values, usingnnz(a)
spares you 2 chars compared tonumel(a)
. - Prefer
a(a==0)
toa(find(a==0))
. ~t
is shorter thant==0
, and even~~t
is shorter thant!=0
.0*(1:n)
is shorter thanzeros(1,n)
Generally,
||
and&&
, unlike many other operators, scalarize the result when the first argument is a scalar. For matrices, only non-empty matrices without elements equal to zero have the logical value of true.Hence, we can do
0||m
instead ofall(all(m))
for any matrix.Try with
0||[1 1;1 0]
and0||[1 1;1 1]
to convince yourself.When you are using a builtin a number of times, do a function handle to spare characters eg.
f=@find
. For short function names at least 3 occurrences justify this, for long ones - even with two occurrences.When a function is a single statement, prefer
f=@(n)dosomething(n)
notation tofunction r=f(n)r=dosomething(n);end
one.Unfortunately, global variables have to be declared both in global scope and in each function using them. But there is an exception: anonymous
@(n)...
functions "see" all variables from the scope where they are called from.It's possible to do
f(a=0,b=0)
instead ofa=0;b=0;f(a,b)
.This seems undocumented feature, but the order of evaluation is from left to right (checked at v. 3.8.1), you can do
zeros(a=n,b=a*a)
to both create a n x n^2 matrix and store it's row and column number ina
andb
variables.The operator precedence table is your friend. Don't do
b=(a==0)
sinceb=a==0
is the same.
Using argument list:
Octave is capable to get default arguments so expressions can be evaluated in the argument list.
This feature is useful when we want to compute an expression and use it multiple times:
f = @(x,a=sort(x))a(a>.5);
One use case is when we use an indexed assignment to modify part of an array and we want to use the array:
a=[1 2 3 4]
a(2)=5;
But the expression (a(2)=5)
returns a(2)
, or the expression (a([1 3])=4)
returns a two elements array. Neither returns the whole array. We can use the argument list:
f=@(a=[1 2 3 4],b=a(2)=5)a;
Here the result of the indexed assignment is stored into a dummy variable b
and the function returns the array.
I do not remember in what challenge I saw it someone use (please tell us=), but I found this a neat trick:
Usually if you add matrices you have to have the same size, but for one dimensional (1xn and nx1) matrices there is a shortcut (that does not work in Matlab):
z = (1:5)+(6:10)';
produces the same effect as
[x,y]=meshgrid(1:5,6:10);
z = x+y;
Then something that pawel.boczarski already mentioned: In Octave you can (while you cannot in Matlab) define auxiliary variables within function handles, AND a variable assignment itself has the value of the assignment so you can really shorten code (well this is an useless example but you'll get the trick):
f=@(n)(z=n+1)*z; %returns (n+1)^2
Then another trick (also applicable in Matlab) is abusing strings for storing (hardcoded) numbers (this neat trick is stolen from feersum), you just need something that interprets the string as number, which is as easy as e.g. adding zero:
a = 'abc';
a+0 %returns
[97 98 99]
Or
sum('abc') == 294
-
\$\begingroup\$ I believe it's supposed to be
a+0
, nota+'0'
. Other than that the tips are nice =) \$\endgroup\$ Commented Nov 6, 2015 at 15:44 -
\$\begingroup\$ Right, thanks! PS: Could you add the
+= -= /=
etc operators in your list below? \$\endgroup\$– flawrCommented Nov 6, 2015 at 17:00 -
1
Skip semicolons!
I'll use this answer to illustrate the point.
The original code was:
function f(x);if~movefile('f.m',x);disp("+-+\n| |\n+-+");end
After removing semicolons, it could be reduced to the following, saving three bytes:
function f(x)if~movefile('f.m',x)disp("+-+\n| |\n+-+")end
This can be used quite a few places, and stuff you don't even try because it looks like a syntax error often works.
-
1\$\begingroup\$ stuff you don't even try because it looks like a syntax error often works Octave in a nutshell \$\endgroup\$ Commented Aug 25, 2017 at 9:05
-In Octave it is possible to apply indexing on a temporary expression, a feature that prohibited in MATLAB and this feature is very useful for golfing. example:
Octave: [1 23 4 5 7](3:4)
and its MATLAB equivalent: a=[1 23 4 5 7];a(3:4)
Octave: hilb(4)(4:5,4:5)
and its MATLAB equivalent: h=hilb(4);h(4:5,4:5)
Octave: {1,4,{4 5 6},[7 ;3]}{3}
and its MATLAB equivalent: a={1,4,{4 5 6},[7 ;3]};a{3}
Octave: num2cell([1 2 3 4]){:}
for creation of comma separated list
Octave: a'(:)'
-Sometimes in an anonymous function as of a normal function we require to evaluate multiple expressions,that include assignment, One approach is that we can place each expression in a cell(since cell can contain object of multiple types ) and when we need the value of each expression we can use indexing to extract that element.
{1,4,{4 5 6},[7 ;3]}{3}
or
{a=1,b=4,c={4 5 6},[b ;3]}{4}
-
\$\begingroup\$ @StewieGriffin Nice tip! Answer updated! \$\endgroup\$– rahnema1Commented Apr 23, 2018 at 11:27
This is a simple, but useful one.
In Octave, but not MATLAB, you can do as in C++:
x = 0 -> x = 0
x++ -> ans = 0
x -> x = 1
++x -> ans = 2
x -> x = 2
Use the e
function instead of ones
or zeros
Octave has an e
function, which I don't think is very well known. It's like ones
or zeros
, but it produces copies of the number e. And it's shorter. This function can be useful sometimes:
- Instead of
ones(m,n)
you can use~~e(m,n)
if you can get away with havingtrue
instead of1
. Or even usee(m,n)
directly if all you need is a nonzero value, not specifically1
(for example if you are going to convert tological
later). - Instead of
zeros(m,n)
you can use~e(m,n)
iffalse
is acceptable instead of0
; or+~e(m,n)
to produce actual zeros.
-
\$\begingroup\$ I'm trying to imagine why this is in Octave. seems weird to me. Or it did until I found that the same is true for other random constants like
pi
,I
(1i
),NaN
,Inf
,eps
,realmax
,realmin
... \$\endgroup\$– GiuseppeCommented Sep 25, 2020 at 21:40 -
1\$\begingroup\$ @Giuseppe Indeed. To me
e
is the weirdest because it doesn't even exist as a scalar in Matlab (the others do) \$\endgroup\$ Commented Sep 25, 2020 at 21:50
Another simple, but useful one (not possible in MATLAB):
Assign the same value to several variables:
a=b=c=0;
Use eval
!
Inspired by Luis Mendo's answer here.
Anonymous functions are in most cases shorter than creating a script that needs one or more calls to input('')
. The downside is that loops and variable modifications (such as swapping two elements in a matrix) is impossible cumbersome.
With eval
, you can fetch the input as you do with a normal anonymous function, and run the script as you do with a normal script:
Consider this:
c=(i=@input)('');N=i('');A=i('');for C=c,A(flip(k))=A(k=[x=find(A==C),N^2+1-x]);end,A
Compared to this:
@(c,N,A)eval('for C=c,A(flip(k))=A(k=[x=find(A==C),N^2+1-x]);end,A')
The code is identical, but the input section is much shorter.
This can also be used to modify input variables, like this (credit to Luis Mendo for this!):
f(x)eval('x([1,4])=x([4,1])`;
-
3\$\begingroup\$ The code is identical Only uglier, slower, and less readable. What more can you ask for? :-D \$\endgroup\$ Commented Apr 23, 2018 at 13:31
Related, but not identical tips for MATLAB.
A little known and little used feature of Octave is that most builtin functions can be called without parentheses, in which case they will treat whatever follows it as a string (as long as it doesn't contain spaces). If it contains spaces you need quotation marks. This can frequently be used to save a byte or two when using disp
. All the following work, and gives the same result:
disp('Hello')
disp Hello
disp"Hello"
If you have spaces, then you must have the quotation marks:
disp('Hello, World!')
disp"Hello, World!"
Other, less useful examples include:
nnz PPCG
ans = 4
size PPCG
ans = 1 4
str2num 12
ans = 12