Thread overview
std.algorithm.remove from array of custom classes?
Dec 09, 2015
Tim K.
Dec 09, 2015
BBaz
Dec 09, 2015
Tim K.
Dec 09, 2015
Andrea Fontana
Dec 09, 2015
cym13
Dec 09, 2015
Andrea Fontana
December 09, 2015
Hi!

I'm trying to remove an item from an array of objects. But I get error messages when compiling (see below) which I do not understand. I figured I had to override opEquals for it to work, but no.
How do I get this to work?

Regards



    class A
    {
        this(string si, uint ui) { s = si; u = ui; }
        string s;
        uint u;

        override bool opEquals(Object obj)
        {
            A o = cast(A)obj;
            return (s == o.s) && (u == o.u);
        }
    }

    int main(string[] argv)
    {
        import std.stdio: writeln;
        import std.algorithm: remove;
        A a = new A("a", 1);
        A b = new A("b", 2);
        A[] as = [a, b];
        as.remove(a);
        writeln(as);

        return 0;
    }


Error:

/usr/include/dmd/phobos/std/algorithm/mutation.d(1503): Error: template std.range.primitives.popFrontExactly cannot deduce function from argument types !()(A[], A), candidates are:
/usr/include/dmd/phobos/std/range/primitives.d(1791):        std.range.primitives.popFrontExactly(Range)(ref Range r, size_t n) if (isInputRange!Range)
/usr/include/dmd/phobos/std/algorithm/mutation.d(1504): Error: template std.range.primitives.popFrontExactly cannot deduce function from argument types !()(A[], A), candidates are:
/usr/include/dmd/phobos/std/range/primitives.d(1791):        std.range.primitives.popFrontExactly(Range)(ref Range r, size_t n) if (isInputRange!Range)
/usr/include/dmd/phobos/std/algorithm/mutation.d(1505): Error: cannot implicitly convert expression (from) of type dummy.A to ulong
dummy.d(21): Error: template instance std.algorithm.mutation.remove!(cast(SwapStrategy)2, A[], A) error instantiating

December 09, 2015
On Wednesday, 9 December 2015 at 13:05:31 UTC, Tim K. wrote:
> Hi!
>
> I'm trying to remove an item from an array of objects. But I get error messages when compiling (see below) which I do not understand. I figured I had to override opEquals for it to work, but no.
> How do I get this to work?

You should read the documentation, there is two errors:

1) remove works with an index
2) remove does not remove in place

so with

~~~~~~~~~~~~~~~~~~~~~~~~~~
import std.stdio;
import std.algorithm;

class A
{
    this(string si, uint ui) { s = si; u = ui; }
    string s;
    uint u;

    override bool opEquals(Object obj) const
    {
        if (A o = cast(A)obj)
            return (s == o.s) && (u == o.u);
        else
            return false;
    }
}

void main(string[] argv)
{
    A a = new A("a", 1);
    A b = new A("b", 2);
    A[] as = [a, b];
    as = as.remove(0);
    writeln(as);
}
~~~~~~~~~~~~~~~~~~~~~~~~~~

also, off topic but 2 other advices/errors

3) opEquals can be 'const' because the method doesn't mutate the state of the object
4) your cast wasn't safe


http://dlang.org/phobos/std_algorithm_mutation.html#.remove
December 09, 2015
On Wednesday, 9 December 2015 at 13:13:36 UTC, BBaz wrote:

> 1) remove works with an index
I guess I did read it wrong. Sorry.
Is there a convenience function that allows me to remove an/all object(s) with a certain value from an array or do I need to write one myself?

> 2) remove does not remove in place
That's fine.

December 09, 2015
On Wednesday, 9 December 2015 at 13:23:00 UTC, Tim K. wrote:
> On Wednesday, 9 December 2015 at 13:13:36 UTC, BBaz wrote:
>
>> 1) remove works with an index
> I guess I did read it wrong. Sorry.
> Is there a convenience function that allows me to remove an/all object(s) with a certain value from an array or do I need to write one myself?
>
>> 2) remove does not remove in place
> That's fine.

void main(string[] argv)
{
    A a = new A("a", 1);
    A b = new A("b", 2);
    A[] as = [a, b];
    as = as.remove!(x => x == a);
    writeln(as);
}

If array is sorted you can find the index of that element and then remove it by index.
December 09, 2015
On Wednesday, 9 December 2015 at 13:13:36 UTC, BBaz wrote:
> 3) opEquals can be 'const' because the method doesn't mutate the state of the object
> 4) your cast wasn't safe
>
>
> http://dlang.org/phobos/std_algorithm_mutation.html#.remove

Maybe something like this works better:

...

    override bool opEquals(T)(T obj) const
    if (is(T : A))
    {
        return (s == o.s) && (u == o.u);
    }

...
December 09, 2015
On Wednesday, 9 December 2015 at 13:23:00 UTC, Tim K. wrote:
> On Wednesday, 9 December 2015 at 13:13:36 UTC, BBaz wrote:
>
> Is there a convenience function that allows me to remove an/all object(s) with a certain value from an array or do I need to write one myself?

Here are some elements of strategy:

     import std.algorithm;
     import std.array;

     auto arr = [2, 3, 4, 5, 3, 2, 4];

     // Remove all
     arr = arr.remove!(x => x==3);
     assert(arr == [2, 4, 5, 2, 4];);

     // remove all (filter works lazilly, we use array to get an array nonetheless)
     // filter is useful when composing functions, not so much here
     arr = arr.filter!(x => x==2).array;
     assert(arr == [4, 5, 4]);

     // Remove one, throw if the element is not found,
     // we use countUntil to get the index.
     arr = arr.remove(arr.countUntil(4));
     assert(arr == [5, 4]);

also you may be interested in reading this:

http://p0nce.github.io/d-idioms/#Adding-or-removing-an-element-from-arrays