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.
-
2\$\begingroup\$ Related, but not a duplicate: Tips for golfing in MATLAB \$\endgroup\$Dennis Jaheruddin– Dennis Jaheruddin2014年01月29日 10:16:18 +00:00Commented Jan 29, 2014 at 10:16
11 Answers 11
- Once you know, that
ais free of zero values, usingnnz(a)spares you 2 chars compared tonumel(a). - Prefer
a(a==0)toa(find(a==0)). ~tis shorter thant==0, and even~~tis 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||minstead 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);endone.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 inaandbvariables.The operator precedence table is your friend. Don't do
b=(a==0)sinceb=a==0is 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\$Stewie Griffin– Stewie Griffin2015年11月06日 15:44:46 +00:00Commented Nov 6, 2015 at 15:44 -
\$\begingroup\$ Right, thanks! PS: Could you add the
+= -= /=etc operators in your list below? \$\endgroup\$flawr– flawr2015年11月06日 17:00:03 +00:00Commented Nov 6, 2015 at 17:00 -
1\$\begingroup\$
+ais shorter thana+0\$\endgroup\$Luis Mendo– Luis Mendo2016年04月27日 13:56:41 +00:00Commented Apr 27, 2016 at 13:56
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\$Sanchises– Sanchises2017年08月25日 09:05:42 +00:00Commented 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\$rahnema1– rahnema12018年04月23日 11:27:17 +00:00Commented 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 onesor 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 havingtrueinstead 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 tologicallater). - Instead of
zeros(m,n)you can use~e(m,n)iffalseis 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\$Giuseppe– Giuseppe2020年09月25日 21:40:58 +00:00Commented Sep 25, 2020 at 21:40 -
1\$\begingroup\$ @Giuseppe Indeed. To me
eis the weirdest because it doesn't even exist as a scalar in Matlab (the others do) \$\endgroup\$Luis Mendo– Luis Mendo2020年09月25日 21:50:21 +00:00Commented 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 rows(a) instead of size(a,1)
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\$Luis Mendo– Luis Mendo2018年04月23日 13:31:27 +00:00Commented 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