18
\$\begingroup\$

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.

\$\endgroup\$

10 Answers 10

9
\$\begingroup\$
  1. Once you know, that a is free of zero values, using nnz(a) spares you 2 chars compared to numel(a).
  2. Prefer a(a==0) to a(find(a==0)).
  3. ~t is shorter than t==0 , and even ~~t is shorter than t!=0.
  4. 0*(1:n) is shorter than zeros(1,n)
  5. 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 of all(all(m)) for any matrix.

Try with 0||[1 1;1 0] and 0||[1 1;1 1] to convince yourself.

  1. 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 occurences justify this, for long ones - even with two occurences.

  2. When a function is a single statement, prefer f=@(n)dosomething(n) notation to function r=f(n)r=dosomething(n);end one.

  3. 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.

  4. It's possible to do f(a=0,b=0) instead of a=0;b=0;f(a,b).

  5. 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 in a and b variables.

  6. The operator precedence table is your friend. Don't do b=(a==0) since b=a==0 is the same.

\$\endgroup\$
7
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ I believe it's supposed to be a+0, not a+'0'. Other than that the tips are nice =) \$\endgroup\$ – Stewie Griffin Nov 6 '15 at 15:44
  • \$\begingroup\$ Right, thanks! PS: Could you add the += -= /= etc operators in your list below? \$\endgroup\$ – flawr Nov 6 '15 at 17:00
  • 1
    \$\begingroup\$ +a is shorter than a+0 \$\endgroup\$ – Luis Mendo Apr 27 '16 at 13:56
7
\$\begingroup\$

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.

\$\endgroup\$
6
\$\begingroup\$

-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}

\$\endgroup\$
  • \$\begingroup\$ @StewieGriffin Nice tip! Answer updated! \$\endgroup\$ – rahnema1 Apr 23 '18 at 11:27
5
\$\begingroup\$

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.

\$\endgroup\$
  • 1
    \$\begingroup\$ stuff you don't even try because it looks like a syntax error often works Octave in a nutshell \$\endgroup\$ – Sanchises Aug 25 '17 at 9:05
2
\$\begingroup\$

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
\$\endgroup\$
2
\$\begingroup\$

Another simple, but useful one (not possible in MATLAB):

Assign the same value to several variables:

a=b=c=0;
\$\endgroup\$
2
\$\begingroup\$

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])`;
\$\endgroup\$
  • 3
    \$\begingroup\$ The code is identical Only uglier, slower, and less readable. What more can you ask for? :-D \$\endgroup\$ – Luis Mendo Apr 23 '18 at 13:31
1
\$\begingroup\$

Use rows(a) instead of size(a,1)

\$\endgroup\$
1
\$\begingroup\$

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
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.