On 01/05/2016 10:47 AM, Charles Smith wrote:

>          auto result = 1_000.iota.map!(a => a.repeat(count(arr[],
> a))).chain.array;

You are traversing the array per index value (1000 times), which can be done once up front:

enum elementCount = 1_000_000;
enum valueCount = 1000;

void main() {
    import std.conv : to;
    import std.datetime;
    import std.random;
    import std.stdio;

    int[elementCount] arr;

    for(int i; i < arr.length; ++i)
        arr[i] = uniform(0, valueCount);

    // Now they get their own arrays:
    auto benchmarks = benchmark!(() => algorithmSort(arr.dup),
                                 () => countingSort(arr.dup))(1);

    writeln("Algorithm's Sort: ", to!Duration(benchmarks[0]));
    writeln("Counting Sort   : ", to!Duration(benchmarks[1]));
}

auto algorithmSort(int[] arr) {
    import std.algorithm : sort, sum;

    auto result = sort(arr[]);
    return result.sum;
}

auto countingSort(int[] arr) {
    import std.algorithm : count, map, joiner, sum, each;
    import std.range : array, repeat, enumerate;

    uint[valueCount] hist;
    arr.each!(a => ++hist[a]);

    auto result = hist[].enumerate.map!(t => t[0].repeat(t[1])).joiner;
    // To make sure that we consume the lazy range:
    return result.sum;
}

> 2. I noticed that result within `countingSort` is an array of arrays. I
> thought `chain` would concat them... did I miss something obvious?

I think .joiner is what you're looking for.

> 3. It's kind of hard to compare performance because of (1), but is there
> a better way to do this?

I changed the code to pass each function a different array.

My results with -O -inline -noboundscheck:

Algorithm's Sort: 76 ms, 910 μs, and 8 hnsecs
Counting Sort   : 21 ms, 563 μs, and 9 hnsecs

Ali

Reply via email to