October 31, 2011 Re: std.container & ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dmitry Olshansky | On Mon, 31 Oct 2011 05:16:11 -0400, Dmitry Olshansky <dmitry.olsh@gmail.com> wrote:
> On 31.10.2011 11:16, Tobias Pankrath wrote:
>> Jonathan M Davis wrote:
>>
>>> find allows
>>> you to do that just fine, and such a remove function would simply be
>>> duplicating its functionality.
>>
>> But this thread serves as a proof that it is not obvious and something like
>> containers should be obvious to use. Deleting an element with a certain
>> value is a common task and should should not take
>> three function calls, with functions from three different modules.
>>
>>> You would be doing exactly the same thing in C++ except that it would be
>>> with an iterator rather than a range. You would use find to find the
>>> iterator to the element that you wanted and then you'd pass that to the
>>> list's erase function.
>> I don't think we should refer to C++ as an benchmark for ease of use.
>>
>> How do you delete every occurence of v? Not just the first one? Is this
>> equally "easy" with find and take? I didn't find an easy way not
>> envolving a loop within 10 Minutes by reading the documentation.
>
> It is, let's use remove from std.algorithm! ... though there is no overload of remove for forward ranges ... crap, worthy of bugzilla report. Or SList could be special enough to offer a built-in remove with predicate done in O(n).
>
> However this should work( yet because of apparent bug in SList it doesn't). The bug is:
> Line 1294 of std.container should be:
> for (; !r.empty; r.popFront())
> ...
> or it will remove the whole container.
>
> Code:
> import std.container, std.range;
> import std.functional, std.algorithm, std.stdio;
>
> void removeFromList(alias pred, T)(ref SList!T s)
> {
> static if(is(typeof(pred) == string))
> alias unaryFun!pred Pred;
> else
> alias pred Pred;
> for(auto r=s[]; !r.empty; )
> {
> if(Pred(r.front))
> {
> r = s.linearRemove(take(r,1));
> continue;
> }
> else
> r.popFront();
> }
> }
>
> void main()
> {
> SList!int list(20, 30, 40, 50, 60); // will work with stock Phobos if the first element % 20 != 0
> removeFromList!"a % 20 == 0"(list);
> writeln(list[]);
>
> }
>
> And more importantly, it still would be horribly slow O(N^2). Personally, because of that I'd prefer hand-rolled intrusive singly-linked list any time of day.
ahem, using dcollections:
foreach(ref doRemove, cell; &organism.purge)
doRemove = cell.x == x && cell.y == y;
complexity: O(n)
:)
-Steve
|
October 31, 2011 Re: std.container & ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 31.10.2011 18:38, Steven Schveighoffer wrote: > On Mon, 31 Oct 2011 05:16:11 -0400, Dmitry Olshansky > <dmitry.olsh@gmail.com> wrote: > >> On 31.10.2011 11:16, Tobias Pankrath wrote: >>> Jonathan M Davis wrote: >>> >>>> find allows >>>> you to do that just fine, and such a remove function would simply be >>>> duplicating its functionality. >>> >>> But this thread serves as a proof that it is not obvious and >>> something like >>> containers should be obvious to use. Deleting an element with a certain >>> value is a common task and should should not take >>> three function calls, with functions from three different modules. >>> >>>> You would be doing exactly the same thing in C++ except that it >>>> would be >>>> with an iterator rather than a range. You would use find to find the >>>> iterator to the element that you wanted and then you'd pass that to the >>>> list's erase function. >>> I don't think we should refer to C++ as an benchmark for ease of use. >>> >>> How do you delete every occurence of v? Not just the first one? Is this >>> equally "easy" with find and take? I didn't find an easy way not >>> envolving a loop within 10 Minutes by reading the documentation. >> >> It is, let's use remove from std.algorithm! ... though there is no >> overload of remove for forward ranges ... crap, worthy of bugzilla >> report. Or SList could be special enough to offer a built-in remove >> with predicate done in O(n). >> >> However this should work( yet because of apparent bug in SList it >> doesn't). The bug is: >> Line 1294 of std.container should be: >> for (; !r.empty; r.popFront()) >> ... >> or it will remove the whole container. >> >> Code: >> import std.container, std.range; >> import std.functional, std.algorithm, std.stdio; >> >> void removeFromList(alias pred, T)(ref SList!T s) >> { >> static if(is(typeof(pred) == string)) >> alias unaryFun!pred Pred; >> else >> alias pred Pred; >> for(auto r=s[]; !r.empty; ) >> { >> if(Pred(r.front)) >> { >> r = s.linearRemove(take(r,1)); >> continue; >> } >> else >> r.popFront(); >> } >> } >> >> void main() >> { >> SList!int list(20, 30, 40, 50, 60); // will work with stock Phobos if >> the first element % 20 != 0 >> removeFromList!"a % 20 == 0"(list); >> writeln(list[]); >> >> } >> >> And more importantly, it still would be horribly slow O(N^2). >> Personally, because of that I'd prefer hand-rolled intrusive >> singly-linked list any time of day. > > ahem, using dcollections: > > foreach(ref doRemove, cell; &organism.purge) > doRemove = cell.x == x && cell.y == y; > > complexity: O(n) While computer happily does O(n) work here, my brain screams in cognitive dissonance figuring out that this assignment actually does delete... meh voodoo through and through :) I'd rather organism.remove!((cell){ return cell.x == x && cell.y == y; })(); or something like that. But it's not a question of form, but more of a missing stuff that should be there. > > :) > > -Steve -- Dmitry Olshansky |
October 31, 2011 Re: std.container & ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dmitry Olshansky | Looks like it was accidental cross-posting:
On 31.10.2011 20:11, Alessandro Stamatto wrote:
>
> it still would be horribly slow O(N^2).
> Personally, because of that I'd prefer hand-rolled intrusive
> singly-linked list any time of day.
>
>
> Now you're scaring me... You're saying that SList in D not only is bugged, but
> a templated remove_if would run in O(N^2) instead of O(N) ????!!!!
Basically I'm saying that with current SList *implementation* it will run in O(N^2), because for some reason it always do a check on each range passed to remove that it does belong to this list. (i.e. it walks from head till hits it or it's own tail)
--
Dmitry Olshansky
|
October 31, 2011 Re: std.container & ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dmitry Olshansky | On Mon, 31 Oct 2011 12:40:37 -0400, Dmitry Olshansky <dmitry.olsh@gmail.com> wrote: > On 31.10.2011 18:38, Steven Schveighoffer wrote: >> On Mon, 31 Oct 2011 05:16:11 -0400, Dmitry Olshansky >> <dmitry.olsh@gmail.com> wrote: >> >>> On 31.10.2011 11:16, Tobias Pankrath wrote: >>>> Jonathan M Davis wrote: >>>> >>>>> find allows >>>>> you to do that just fine, and such a remove function would simply be >>>>> duplicating its functionality. >>>> >>>> But this thread serves as a proof that it is not obvious and >>>> something like >>>> containers should be obvious to use. Deleting an element with a certain >>>> value is a common task and should should not take >>>> three function calls, with functions from three different modules. >>>> >>>>> You would be doing exactly the same thing in C++ except that it >>>>> would be >>>>> with an iterator rather than a range. You would use find to find the >>>>> iterator to the element that you wanted and then you'd pass that to the >>>>> list's erase function. >>>> I don't think we should refer to C++ as an benchmark for ease of use. >>>> >>>> How do you delete every occurence of v? Not just the first one? Is this >>>> equally "easy" with find and take? I didn't find an easy way not >>>> envolving a loop within 10 Minutes by reading the documentation. >>> >>> It is, let's use remove from std.algorithm! ... though there is no >>> overload of remove for forward ranges ... crap, worthy of bugzilla >>> report. Or SList could be special enough to offer a built-in remove >>> with predicate done in O(n). >>> >>> However this should work( yet because of apparent bug in SList it >>> doesn't). The bug is: >>> Line 1294 of std.container should be: >>> for (; !r.empty; r.popFront()) >>> ... >>> or it will remove the whole container. >>> >>> Code: >>> import std.container, std.range; >>> import std.functional, std.algorithm, std.stdio; >>> >>> void removeFromList(alias pred, T)(ref SList!T s) >>> { >>> static if(is(typeof(pred) == string)) >>> alias unaryFun!pred Pred; >>> else >>> alias pred Pred; >>> for(auto r=s[]; !r.empty; ) >>> { >>> if(Pred(r.front)) >>> { >>> r = s.linearRemove(take(r,1)); >>> continue; >>> } >>> else >>> r.popFront(); >>> } >>> } >>> >>> void main() >>> { >>> SList!int list(20, 30, 40, 50, 60); // will work with stock Phobos if >>> the first element % 20 != 0 >>> removeFromList!"a % 20 == 0"(list); >>> writeln(list[]); >>> >>> } >>> >>> And more importantly, it still would be horribly slow O(N^2). >>> Personally, because of that I'd prefer hand-rolled intrusive >>> singly-linked list any time of day. >> >> ahem, using dcollections: >> >> foreach(ref doRemove, cell; &organism.purge) >> doRemove = cell.x == x && cell.y == y; >> >> complexity: O(n) > > While computer happily does O(n) work here, my brain screams in cognitive dissonance figuring out that this assignment actually does delete... meh voodoo through and through :) > > I'd rather > organism.remove!((cell){ return cell.x == x && cell.y == y; })(); > or something like that. > But it's not a question of form, but more of a missing stuff that should be there. That could also be added (and I agree it's a good idea). Alas, interface templates still don't work, so it'd have to be defined as a convention. Note that this isn't really the intended usage for purge (though it works quite nicely as an afterthought). Typically, when I use purge, I'm iterating through all the elements, processing them somehow, and then deciding to remove them or not based on the processing. For instance, a main thread processing results from sub-threads, and removing ones that are finished. Think of it as an implementation of Java's Iterator.remove: http://download.oracle.com/javase/7/docs/api/java/util/Iterator.html#remove() -Steve |
November 01, 2011 Re: std.container & ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | Steven Schveighoffer Wrote:
> ahem, using dcollections:
>
> foreach(ref doRemove, cell; &organism.purge)
> doRemove = cell.x == x && cell.y == y;
>
> complexity: O(n)
may be a generic iteration handler would be more useful?
foreach(ref handler, cell; &organism.each)
if(cell.x == x && cell.y == y) handler.removeCurrent();
it could provide a whole api, say, you may want to have lookahead
foreach(ref handler, cell; &organism.each)
if(cell.x == x && cell.y == y && handler.next.x==0)
handler.removeCurrent();
|
November 01, 2011 Re: std.container & ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On 10/30/2011 9:28 PM, Jonathan M Davis wrote:
> On Sunday, October 30, 2011 20:53:02 Max Wolter wrote:
>> Hello there.
>>
>> Thank you very much for the explanation.
>>
>> However, while I really liked the concept of ranges in Andrei's book and
>> a lot of it seems intuitive and faster than using iterators, I can't
>> shake the feeling that in this case, it's just unnecessarily convoluted.
>>
>> Maybe it's just the fact that the container library is still very basic,
>> but I don't think I should go through such a complicated procedure to
>> remove an known element from a list. It's just not a "very simple" or
>> intuitive solution, which is something I came to love D for thus far.
>
> You would be doing exactly the same thing in C++ except that it would be with
> an iterator rather than a range. You would use find to find the iterator to the
> element that you wanted and then you'd pass that to the list's erase function.
> It is only more complicated in D in that you get a range which _starts_ with
> the element that you want (essentially, you get the iterator to that element
> plus the end iterator for the list), so if you want to remove only the first
> element, you take it from the front of the range. Other than that, it's the
> same as in C++. You can't remove an element from a list in C++ by giving that
> element to the list anymore than you can in D. In both cases, you need an
> iterator or a range.
>
> So, in comparison to C++, there's no significant difference. Now, Java does have
> a remove function which will take an element and remove the first occurence of
> that element from a list, and we could theoretically add one, but why? It
> would just be duplicating the functionality that find already gives. Java
> doesn't use iterators the way the C++ does, and it doesn't have ranges, so it
> _can't_ have a find function the way that C++ and D do, but D can. And in some
> cases, find can do it more efficiently than your loop could have.
>
> I grant you that if you're not used to using find like this in C++ (and far,
> far too many C++ programmers use loops instead of find - in part because pre-
> C++11, there were no lambdas and any time you need a custom comparison
> function, it's a pain to get one), then it's not immediately intuitive, but
> it's far more flexible and powerful than removing elements by giving the
> element to a remove function on the list. And if you really want to use a
> loop, then you still can. You just can't use foreach.
>
> for(auto r = organism[]; !r.empty; r.popFront())
> {
> if(r.front.x == x&& r.front.y == y)
> {
> organism.stableLinearRemove(take(r, 1));
> break;
> }
> }
>
> but that's a lot more verbose than simply using find, and as I said, in at
> least some cases, find can be more efficient than simply looping, since it's
> optimized for finding elements.
>
> - Jonathan M Davis
Hello again.
I've read all further replies in this thread, but it seems to me this is the most appropriate place to respond.
Simply put, all of those options are too verbose. If what you want to do is simple, the syntax should also be simple, this is what I love about D. As a side-note, I don't come from Java, but I still expect a container to be able to remove an element by passing it to a method. The verbosity and the details of this operation should be hidden in the implementation of the method and I shouldn't need to know about the details. Otherwise, I could just as well implement my own container.
/Max
|
November 02, 2011 Re: std.container & ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | Kagamin , dans le message (digitalmars.D.learn:30362), a écrit :
> Steven Schveighoffer Wrote:
>
>> ahem, using dcollections:
>>
>> foreach(ref doRemove, cell; &organism.purge)
>> doRemove = cell.x == x && cell.y == y;
>>
>> complexity: O(n)
>
> may be a generic iteration handler would be more useful?
>
> foreach(ref handler, cell; &organism.each)
> if(cell.x == x && cell.y == y) handler.removeCurrent();
>
> it could provide a whole api, say, you may want to have lookahead
>
> foreach(ref handler, cell; &organism.each)
> if(cell.x == x && cell.y == y && handler.next.x==0)
> handler.removeCurrent();
That's not easier than using Tobias' improved foreach:
foreach(cell, cellRange; organism[])
if (cell.x == x && cell.y == y)
organism.remove(cellRange);
If you want to use algorithm specialized and optimized for the container, I would prefer to use purge than each + handler. purge seems better to me, because it can be specialized for the container and for the action, and do not require to learn a new handler structure. "each" do not seem to add a lot to foreach(cell, cellRange; range), since it must be able to cope with any operation provided by handler, and any operation combinaisons...
|
November 02, 2011 Re: std.container & ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Max Wolter | On Tue, 01 Nov 2011 16:53:26 -0400, Max Wolter <awishformore@gmail.com> wrote: > On 10/30/2011 9:28 PM, Jonathan M Davis wrote: >> On Sunday, October 30, 2011 20:53:02 Max Wolter wrote: >>> Hello there. >>> >>> Thank you very much for the explanation. >>> >>> However, while I really liked the concept of ranges in Andrei's book and >>> a lot of it seems intuitive and faster than using iterators, I can't >>> shake the feeling that in this case, it's just unnecessarily convoluted. >>> >>> Maybe it's just the fact that the container library is still very basic, >>> but I don't think I should go through such a complicated procedure to >>> remove an known element from a list. It's just not a "very simple" or >>> intuitive solution, which is something I came to love D for thus far. >> >> You would be doing exactly the same thing in C++ except that it would be with >> an iterator rather than a range. You would use find to find the iterator to the >> element that you wanted and then you'd pass that to the list's erase function. >> It is only more complicated in D in that you get a range which _starts_ with >> the element that you want (essentially, you get the iterator to that element >> plus the end iterator for the list), so if you want to remove only the first >> element, you take it from the front of the range. Other than that, it's the >> same as in C++. You can't remove an element from a list in C++ by giving that >> element to the list anymore than you can in D. In both cases, you need an >> iterator or a range. >> >> So, in comparison to C++, there's no significant difference. Now, Java does have >> a remove function which will take an element and remove the first occurence of >> that element from a list, and we could theoretically add one, but why? It >> would just be duplicating the functionality that find already gives. Java >> doesn't use iterators the way the C++ does, and it doesn't have ranges, so it >> _can't_ have a find function the way that C++ and D do, but D can. And in some >> cases, find can do it more efficiently than your loop could have. >> >> I grant you that if you're not used to using find like this in C++ (and far, >> far too many C++ programmers use loops instead of find - in part because pre- >> C++11, there were no lambdas and any time you need a custom comparison >> function, it's a pain to get one), then it's not immediately intuitive, but >> it's far more flexible and powerful than removing elements by giving the >> element to a remove function on the list. And if you really want to use a >> loop, then you still can. You just can't use foreach. >> >> for(auto r = organism[]; !r.empty; r.popFront()) >> { >> if(r.front.x == x&& r.front.y == y) >> { >> organism.stableLinearRemove(take(r, 1)); >> break; >> } >> } >> >> but that's a lot more verbose than simply using find, and as I said, in at >> least some cases, find can be more efficient than simply looping, since it's >> optimized for finding elements. >> >> - Jonathan M Davis > > Hello again. > > I've read all further replies in this thread, but it seems to me this is the most appropriate place to respond. > > Simply put, all of those options are too verbose. If what you want to do is simple, the syntax should also be simple, this is what I love about D. As a side-note, I don't come from Java, but I still expect a container to be able to remove an element by passing it to a method. The verbosity and the details of this operation should be hidden in the implementation of the method and I shouldn't need to know about the details. Otherwise, I could just as well implement my own container. The basic response to this is, when dealing with containers generically (that is, you know you have a container, but you don't know what type), the "remove this element" operation is not necessarily a good primitive to have. Simply because from the myriad of containers, only some can implement this operation efficiently. Java embeds this operation in the interface, which means any interface you have to a container could potentially use O(n) time to remove that element. Such an innocuous piece of syntax *should* have a cost if it's not efficient IMO. BTW, the original question doesn't provide enough information to say "remove this element." Even in Java, if you aren't using the default comparison, you must use a comparator method to determine which one to remove. If cell.x == x && cell.y == y *is* the comparison operator for the type, then the syntax gets much simpler, because you don't need to pass a specialized comparison function. In dcollections, removing a specific element (using the default comparison operator for that element) on a *fast lookup* container is as simple as: container.remove(container.find(x)); Which removes the element x if it's found. However, this is not defined for containers which use O(n) time to search (such as linked list), you must use std.algorithm.find for that: container.remove(find(container[], x).begin); Should work, and takes O(n) time. -Steve |
November 02, 2011 Re: std.container & ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Nov 2, 2011, at 12:48 PM, Steven Schveighoffer wrote:
>> Hello again.
>>
>> I've read all further replies in this thread, but it seems to me this is the most appropriate place to respond.
>>
>> Simply put, all of those options are too verbose. If what you want to do is simple, the syntax should also be simple, this is what I love about D. As a side-note, I don't come from Java, but I still expect a container to be able to remove an element by passing it to a method. The verbosity and the details of this operation should be hidden in the implementation of the method and I shouldn't need to know about the details. Otherwise, I could just as well implement my own container.
>
> The basic response to this is, when dealing with containers generically (that is, you know you have a container, but you don't know what type), the "remove this element" operation is not necessarily a good primitive to have.
>
> Simply because from the myriad of containers, only some can implement this operation efficiently. Java embeds this operation in the interface, which means any interface you have to a container could potentially use O(n) time to remove that element. Such an innocuous piece of syntax *should* have a cost if it's not efficient IMO.
>
> BTW, the original question doesn't provide enough information to say "remove this element." Even in Java, if you aren't using the default comparison, you must use a comparator method to determine which one to remove. If cell.x == x && cell.y == y *is* the comparison operator for the type, then the syntax gets much simpler, because you don't need to pass a specialized comparison function.
>
> In dcollections, removing a specific element (using the default comparison operator for that element) on a *fast lookup* container is as simple as:
>
> container.remove(container.find(x));
>
> Which removes the element x if it's found. However, this is not defined for containers which use O(n) time to search (such as linked list), you must use std.algorithm.find for that:
>
> container.remove(find(container[], x).begin);
>
> Should work, and takes O(n) time.
>
> -Steve
I can't really understand what is wrong with an inefficient "remove this element" primitive if it's really what the user had to do...
Once it's in the documentation that the operation is inefficient, why the user must be forced to dig into the newsgroup to find out some code?
Why can't that be furnished in a free function, for example?
Cheers, Paolo
|
November 02, 2011 Re: std.container & ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 11/2/11 8:48 AM, Steven Schveighoffer wrote:
> On Tue, 01 Nov 2011 16:53:26 -0400, Max Wolter <awishformore@gmail.com>
> wrote:
>
>> On 10/30/2011 9:28 PM, Jonathan M Davis wrote:
>>> On Sunday, October 30, 2011 20:53:02 Max Wolter wrote:
>>>> Hello there.
>>>>
>>>> Thank you very much for the explanation.
>>>>
>>>> However, while I really liked the concept of ranges in Andrei's book
>>>> and
>>>> a lot of it seems intuitive and faster than using iterators, I can't
>>>> shake the feeling that in this case, it's just unnecessarily
>>>> convoluted.
>>>>
>>>> Maybe it's just the fact that the container library is still very
>>>> basic,
>>>> but I don't think I should go through such a complicated procedure to
>>>> remove an known element from a list. It's just not a "very simple" or
>>>> intuitive solution, which is something I came to love D for thus far.
>>>
>>> You would be doing exactly the same thing in C++ except that it would
>>> be with
>>> an iterator rather than a range. You would use find to find the
>>> iterator to the
>>> element that you wanted and then you'd pass that to the list's erase
>>> function.
>>> It is only more complicated in D in that you get a range which
>>> _starts_ with
>>> the element that you want (essentially, you get the iterator to that
>>> element
>>> plus the end iterator for the list), so if you want to remove only
>>> the first
>>> element, you take it from the front of the range. Other than that,
>>> it's the
>>> same as in C++. You can't remove an element from a list in C++ by
>>> giving that
>>> element to the list anymore than you can in D. In both cases, you
>>> need an
>>> iterator or a range.
>>>
>>> So, in comparison to C++, there's no significant difference. Now,
>>> Java does have
>>> a remove function which will take an element and remove the first
>>> occurence of
>>> that element from a list, and we could theoretically add one, but
>>> why? It
>>> would just be duplicating the functionality that find already gives.
>>> Java
>>> doesn't use iterators the way the C++ does, and it doesn't have
>>> ranges, so it
>>> _can't_ have a find function the way that C++ and D do, but D can.
>>> And in some
>>> cases, find can do it more efficiently than your loop could have.
>>>
>>> I grant you that if you're not used to using find like this in C++
>>> (and far,
>>> far too many C++ programmers use loops instead of find - in part
>>> because pre-
>>> C++11, there were no lambdas and any time you need a custom comparison
>>> function, it's a pain to get one), then it's not immediately
>>> intuitive, but
>>> it's far more flexible and powerful than removing elements by giving the
>>> element to a remove function on the list. And if you really want to
>>> use a
>>> loop, then you still can. You just can't use foreach.
>>>
>>> for(auto r = organism[]; !r.empty; r.popFront())
>>> {
>>> if(r.front.x == x&& r.front.y == y)
>>> {
>>> organism.stableLinearRemove(take(r, 1));
>>> break;
>>> }
>>> }
>>>
>>> but that's a lot more verbose than simply using find, and as I said,
>>> in at
>>> least some cases, find can be more efficient than simply looping,
>>> since it's
>>> optimized for finding elements.
>>>
>>> - Jonathan M Davis
>>
>> Hello again.
>>
>> I've read all further replies in this thread, but it seems to me this
>> is the most appropriate place to respond.
>>
>> Simply put, all of those options are too verbose. If what you want to
>> do is simple, the syntax should also be simple, this is what I love
>> about D. As a side-note, I don't come from Java, but I still expect a
>> container to be able to remove an element by passing it to a method.
>> The verbosity and the details of this operation should be hidden in
>> the implementation of the method and I shouldn't need to know about
>> the details. Otherwise, I could just as well implement my own container.
>
> The basic response to this is, when dealing with containers generically
> (that is, you know you have a container, but you don't know what type),
> the "remove this element" operation is not necessarily a good primitive
> to have.
>
> Simply because from the myriad of containers, only some can implement
> this operation efficiently. Java embeds this operation in the interface,
> which means any interface you have to a container could potentially use
> O(n) time to remove that element. Such an innocuous piece of syntax
> *should* have a cost if it's not efficient IMO.
>
> BTW, the original question doesn't provide enough information to say
> "remove this element." Even in Java, if you aren't using the default
> comparison, you must use a comparator method to determine which one to
> remove. If cell.x == x && cell.y == y *is* the comparison operator for
> the type, then the syntax gets much simpler, because you don't need to
> pass a specialized comparison function.
>
> In dcollections, removing a specific element (using the default
> comparison operator for that element) on a *fast lookup* container is as
> simple as:
>
> container.remove(container.find(x));
>
> Which removes the element x if it's found. However, this is not defined
> for containers which use O(n) time to search (such as linked list), you
> must use std.algorithm.find for that:
>
> container.remove(find(container[], x).begin);
>
> Should work, and takes O(n) time.
>
> -Steve
I don't really understand what's wrong with inefficient methods. You can have inefficient methods that are convenient, like removing an element by the default comparison, or giving it a delegate to match the element(s) to remove.
You profile your application. Is that method the bottle-neck? If so, you change it to a more efficient one. If not, you are happy you had that method there, performing in an inefficient way, but which doesn't matter that much compared to, say, opening an SQL connection.
Programmers want to program, fast. They have schedules, they need to deliver. They don't need to always find the best solution. They can find a compromise between "working" and "fast", move on, and later profile and worry about what matters most.
Programmers don't want to fight with the language or think "Oh, so to remove an element I need to use this operation and combine it with that one and with that other one"...
|
Copyright © 1999-2021 by the D Language Foundation