On 12/20/2013 04:47 PM, aldanor wrote:

> Is there an efficient method to remove elements with multiple
> (compile-time-unknown) indices from an array? I currently do something like
>
>          if (!index.empty)
>              foreach (i; index.sort.reverse)
>                  a = a.remove(i);


That's probably a bug, right? The indexes would probably become off as the array gets shorter.

> ... which looks a bit awkward.

I am sure others can come up with solutions but I can't think of a way of doing this Phobos right now. :)

Here is a range that does what you want (not very well tested ;) ):

import std.stdio;
import std.array;
import std.range;
import std.algorithm;

struct SkipIndexes(R, I)
{
    alias SortedIndexRange = typeof((I.init).sort.uniq);

    R range;
    SortedIndexRange indexes;
    size_t currentIndex;

    this(R range, I indexes, size_t currentIndex = 0)
    {
        this.range = range;
        this.indexes = indexes.sort.uniq;
        this.currentIndex = currentIndex;

        prime();
    }

    bool empty() const @property
    {
        return range.empty;
    }

    ElementType!R front() const @property
    {
        return range.front;
    }

    void prime()
    {
while (!empty && !indexes.empty && (indexes.front == currentIndex)) {
            range.popFront();
            indexes.popFront();
            ++currentIndex;
        }
    }

    void popFront()
    {
        range.popFront();
        ++currentIndex;
        prime();
    }

    auto save() @property
    {
        return this;
    }

    void report() const
    {
        writeln(indexes);
        writeln(currentIndex);
    }
}

auto skipIndexes(R, I)(R range, I skipIndexes, size_t currentIndex = 0)
{
    return SkipIndexes!(R, I)(range, skipIndexes, currentIndex);
}

void main()
{
    auto arr = [ 0, 1, 2, 3, 4, 5 ];
    size_t[] badIndexes = [ 0, 1, 5 ];

    auto skipped = arr.skipIndexes(badIndexes);

    // skipped is a lazy range:
    assert(skipped.equal([ 2, 3, 4 ]));

    // arr is untouched at this point:
    assert(arr == [ 0, 1, 2, 3, 4, 5 ]);

    // To affect it, assign from .array of the lazy range:
    arr = skipped.array;
    assert(arr == [ 2, 3, 4 ]);
}

Ali

Reply via email to