On 01/28/2018 02:52 PM, aliak wrote:
> Hello, I'm trying to write a function called "pull" that, given 2
> ranges, "pull"s the values from range 2 out of range 1. I'm not sure if
> I'm doing it correctly though, and I have some questions so any help is
> appreciated. This is what I have:
>
> ref pull(R1, R2)(return ref R1 r1, R2 r2) {
>      import std.algorithm, std.array, std.range;
>      int numFound = 0;
>      auto r = r1.save;
>      ElementType!R1[] unfoundElements;
>      foreach (e; r) {
>          if (!r2.canFind(e)) {
>              unfoundElements ~= e;
>          } else {
>              numFound++;
>          }
>      }
>      moveEmplaceAll(unfoundElements, r1);
>      r1.popBackN(numFound);
>      return r1;
> }
>
> So my questions are:
>
> 1) So first of all, is there a function like this in phobos that I can
> use? From what I understand phobos is supposed to be nogc so mutating
> functions like these are usually in place ones?

I think the following trivial wrapper around std.algorithm.remove() should do:

void removeMatching(R, N)(ref R r, N needles) {
    import std.algorithm : remove, canFind;
    r = r.remove!(e => needles.canFind(e));
}

void main() {
    auto arr = [1, 2, 3, 2, 4];
    arr.removeMatching([2, 3]);
    assert(arr == [1, 4]);
}

> 2) Is there a way to avoid the extra "moveEmplaceAll" call towards the
> end and still get the same results?

I'm not convinced that unfoundElements is needed at all. :)

> 3) Is it necessary to always import std.array (or std.range: empty,
> front) when doing work like this with range algorithms? (otherwise you
> get no property save when an array is used as a range)

I think importing std.range works as well.

> 6) It will not work when I pass in a range that has const elements.
>
> ie:
>
> const(int)[] arr = [1, 2, 3, 4, 5];
> arr.pull([2, 3]);
>
> This I guess makes sense because moveEmplaceAll depends on isInputRange
> and from my understanding, a const range cannot be one (is that
> correct?).

Yes but your range is not const, the elements are. So, although const(int)[] is a range, it does not have mutable elements.

> So am I correct in thinking there really is no way around
> this, or is there some move/cast trickery that I can use maybe?

You don't want to mutate const elements anyway. It would be breaking a promise that other parts of the program may be depending on. I would return a filtered-out range:

import std.algorithm;

void main() {
    const(int)[] arr = [1, 2, 3, 2, 4];
    auto result = arr.filter!(e => ![2, 3].canFind(e));
    assert(result.equal([1, 4]));
}

If needed, the caller can easily make an array out of the filtered range and the element types will still be const(int):

    import std.range;
    auto arr2 = result.array();
    static assert(is(typeof(arr2) == const(int)[]));

>
> Cheers,
> - Ali

Ali

Reply via email to