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