7

I need to generate multiple results but one at a time, as opposed to everything at once in an array.

How do I do that in Matlab with a generator like syntax as in Python?

NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
user3191455
  • 111
  • 1
  • 2
  • 7
    I don't think Matlab has lazy evaluation. – senshin Jan 13 '14 at 18:54
  • Take a look at varargout, this will probably solve your problem. – Daniel Jan 13 '14 at 20:18
  • 2
    varargout won't solve the problem if it is a shortage of memory. – Frames Catherine White Feb 05 '15 at 04:50
  • Some related references: [Coroutine](https://en.wikipedia.org/wiki/Coroutine), [Generator](https://en.wikipedia.org/wiki/Generator_(computer_programming)), [Iterator](https://en.wikipedia.org/wiki/Iterator), [Lazy evaluation](https://en.wikipedia.org/wiki/Lazy_evaluation) – Amro Nov 15 '16 at 04:09

2 Answers2

13

When executing functions that use the yield keyword, they actually return a generator. Generators are a type of iterators. While MATLAB does not provide the syntax for either, you can implement the "iterator interface" yourself. Here is an example similar to xrange function in python:

classdef rangeIterator < handle
    properties (Access = private)
        i
        n
    end

    methods
        function obj = rangeIterator(n)
            obj.i = 0;
            obj.n = n;
        end

        function val = next(obj)
            if obj.i < obj.n
                val = obj.i;
                obj.i = obj.i + 1;
            else
                error('Iterator:StopIteration', 'Stop iteration')
            end
        end

        function reset(obj)
            obj.i = 0;
        end
    end
end

Here is how we use the iterator:

r = rangeIterator(10);
try
    % keep call next() method until it throws StopIteration
    while true
        x = r.next();
        disp(x);
    end
catch ME
    % if it is not the "stop iteration" exception, rethrow it as an error
    if ~strcmp(ME.identifier,'Iterator:StopIteration')
        rethrow(ME);
    end
end

Note the when using the construct for .. in .. in Python on iterators, it internally does a similar thing.

You could write something similar using regular functions instead of classes, by using either persistent variables or a closure to store the local state of the function, and return "intermediate results" each time it is called.

Amro
  • 123,847
  • 25
  • 243
  • 454
  • Gah, got interrupted by my crying son. I was writing a solution that would accept a function handle as well in the constructor. Anyway, +1 – Jonas Jan 13 '14 at 20:23
  • 1
    If you overload the `size` (returning `[1,n]`) and `subsref` methods on the Iterator appropriately, you can even simply keep the normal `for .. in ...` syntax. – sebastian Jan 14 '14 at 08:31
6

In MATLAB (not yet? in Octave), you can use closures (nested, scoped functions):

function iterator = MyTimeStampedValues(values)

    index = 1;

    function [value, timestamp, done] = next()
        if index <= length(values)
            value = values(index);
            timestamp = datestr(now);
            done = (index == length(values));
            index = index + 1;
        else
            error('Values exhausted');
        end
    end

    iterator = @next;
end

and then

iterator = MyTimeStampedValues([1 2 3 4 5]);
[v, ts, done] = iterator();    % [1, '13-Jan-2014 23:30:45', false]
[v, ts, done] = iterator();    % ...
Wolfgang Kuehn
  • 12,206
  • 2
  • 33
  • 46
  • 1
    This works just well in MATLAB R2013b, but `values` is constructed when `MyTimeStampedValues` is called. So, there isn’t really any lazy evaluation. – Lumen May 12 '14 at 09:23
  • 1
    @Lumen It's not the numbers, it's the timestamps that are lazily generated here in this example. In principle it does the job and yield in Python is just a shortcut for it. What it does is implementing something that keeps state in between calls. – NoDataDumpNoContribution Dec 22 '15 at 22:31