Walter Bright:
> This C++0x article is relevant for comparison:
> http://www.reddit.com/r/programming/comments/8bijk/gcc_c0x_features_exploration/

"Advanced" features have to be used only if they improve the code. I don't like 
that little article and the following discussion.

The following D1 code shows two ways to solve that problem with my dlibs. The 
first code to try is the simplest, that is to scan the data three (or even four 
times):

double avg = cast(double)sum(data) / len(data);
putr("min, max, avg: ", min(data), " ", max(data), " ", avg);

It works with most kind of eager/lazy numerical data, for example a lazy 
generator that has no length. Note that sum() is sometimes faster than a simple 
loop.
In many situations that code (plus some safety against division by zero) is 
good enough.

If you know data is huge or you have found that code to be a bottleneck, and 
you want a single pass you can use something like the following (code written 
on the fly, no unittests present, it may contain bugs):
import d.templates: IsAA, BaseType1, Record;
import d.func: putr, min, max, sum, record, len;
import d.exceptions: EmptyException;


Record!(BaseType1!(TSeq), BaseType1!(TSeq), double) minMaxAvg1(TSeq)(TSeq seq, 
double start=0.0) {
    auto nitems = len(seq);
    if (!nitems)
        throw new EmptyException("minMaxAvg(): 'seq' can't be empty");
    return record(min(seq), max(seq), sum(seq, start) / nitems);
}


Record!(BaseType1!(TSeq), BaseType1!(TSeq), double) minMaxAvg2(TSeq)(TSeq seq, 
double start=0.0) {
    BaseType1!(TSeq) dmin, dmax;
    double dtot = start;
    int nitems;

    static if (IsAA!(TSeq)) {
        foreach (el, _; seq) {
            if (nitems == 0) {
                dmin = el;
                dmax = el;
            }
            if (dmin > el) dmin = el;
            if (dmax < el) dmax = el;
            dtot += el;
            nitems++;
        }
    } else {
        foreach (el; seq) {
            if (nitems == 0) {
                dmin = el;
                dmax = el;
            }
            if (dmin > el) dmin = el;
            if (dmax < el) dmax = el;
            dtot += el;
            nitems++;
        }
    }
    if (!nitems)
        throw new EmptyException("minMaxAvg(): 'seq' can't be empty");
    return record(dmin, dmax, dtot / nitems);
}

void main() {
    int[] data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

    putr("<min, max, avg>: ", minMaxAvg1(data));
    putr("<min, max, avg>: ", minMaxAvg2(data));
}

(Notice the ugly code duplication caused by the AAs).

The output:
min, max, avg: 1 10 5.5
<min, max, avg>: record(1, 10, 5.5)

Bye,
bearophile

Reply via email to