[Issue 13039] combinations

via Digitalmars-d-bugs digitalmars-d-bugs at puremagic.com
Fri Jul 4 04:38:23 PDT 2014


https://issues.dlang.org/show_bug.cgi?id=13039

--- Comment #1 from bearophile_hugs at eml.cc ---
import std.traits: Unqual;

size_t binomial(size_t n, size_t k) pure nothrow @safe @nogc
in {
    assert(n > 0, "binomial: n must be > 0.");
} body {
    if (k < 0 || k > n)
        return 0;
    if (k > (n / 2))
        k = n - k;
    size_t result = 1;
    foreach (size_t d; 1 .. k + 1) {
        result *= n;
        n--;
        result /= d;
    }
    return result;
}

struct CombinationsFixed(size_t k, T) {
    Unqual!T[k] front;
    Unqual!T[] pool;
    size_t n;
    bool empty = false;
    size_t[k] indices;
    size_t len;
    bool lenComputed = false;

    this(T[] pool_) pure nothrow @safe {
        this.pool = pool_.dup; // Can't be @nogc.
        this.n = pool.length;
        if (k > n)
            empty = true;
        foreach (immutable i, ref ini; indices)
            ini = i;
        foreach (immutable i, immutable idx; indices)
            front[i] = pool[idx];
    }

    @property size_t length() /*logic_const*/ pure nothrow @nogc {
        if (!lenComputed) {
            // Set cache.
            len = binomial(n, k);
            lenComputed = true;
        }
        return len;
    }

    void popFront() pure nothrow @safe @nogc {
        if (!empty) {
            bool broken = false;
            size_t pos = 0;
            foreach_reverse (immutable i; 0 .. k) {
                pos = i;
                if (indices[i] != i + n - k) {
                    broken = true;
                    break;
                }
            }
            if (!broken) {
                empty = true;
                return;
            }
            indices[pos]++;
            foreach (immutable j; pos + 1 .. k)
                indices[j] = indices[j - 1] + 1;
            foreach (immutable i, immutable idx; indices)
                front[i] = pool[idx];
        }
    }
}

CombinationsFixed!(k, T) combinationsFixed(size_t k, T)
                                          (T[] items)
in {
    assert(items.length, "combinations: items can't be empty.");
} body {
    return typeof(return)(items);
}

void main() {
    import std.stdio, std.array, std.algorithm;
    [1, 2, 3, 4].combinationsFixed!2.map!(x => x).writeln;
    [1, 2, 3, 4].combinationsFixed!2.array.writeln;
}

--


More information about the Digitalmars-d-bugs mailing list