Re: std.container ranges

2011-11-04 Thread Max Wolter

As long as you don't need to search for the element to remove using its
value, removal in a linked list should be O(1). A linked list that does
not allow O(1) removal and O(1) insertion given a topological reference
is a failure (yes, that includes the current version of SList).


Well, thank god that's cleared up.

Time to move on.

/Max


Re: std.container ranges

2011-11-02 Thread Max Wolter

On 11/2/2011 2:41 PM, Steven Schveighoffer wrote:

On Wed, 02 Nov 2011 09:17:39 -0400, Ary Manzana a...@esperanto.org.ar
wrote:


On 11/2/11 10:12 AM, Steven Schveighoffer wrote:

On Wed, 02 Nov 2011 08:40:19 -0400, Ary Manzana a...@esperanto.org.ar
wrote:


On 11/2/11 8:48 AM, Steven Schveighoffer wrote:


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...


Or use the right container for the job?

Where it really comes into play is generic programming.

Let's say I write some algorithm that removes certain elements from a
container:

removeElements(C, T)(C c, T t[]...)
{
foreach(x; t)
c.remove(t);
}

What's the complexity of this algorithm? For a HashSet, for instance, it
will be O(n) where n is the number of elements to remove.

But for an ArrayList, it will be O(n*m) where m is the number of
elements in c.


But I'm sure in this algorithm I have for this app I'm making, my
collection won't have more than 50 elements. So everything will be
O(1). I need to remove an element from the collection. I really don't
care about the complexity of the operation, because if n is 50,
everything is O(1).


Then your specific application can use std.algorithm.find to implement
the equivalent. Only the algorithm body changes, not the usage of the
algorithm.



Why can't I have an inefficient (for you) remove operation that, for
me, will be ok?


I never said you couldn't (and I've even given examples of such
implementations). It's just not neatly packaged into a method.

But again, if the method is exactly the same as the efficient version
for other containers, it becomes *impossible* to design an algorithm
that guarantees any sort of complexity. As I said before, quadratic sort
is epic fail, and needs to always be avoided.

I'll give you a scenario:

People often complain that Linked List does not have an opIndex on it.
Yes it's inefficient, but so what? I know it's inefficient, let me
decide whether it's worth it or not.

So let's say I add it to LinkList. Those people are happy.

But now, LinkList becomes defined as a *random-access-range* according
to std.ranges. Therefore, std.algorithm.sort(linklist) compiles! And is
now something like O(n^3).

Whereas LinkList already defines a sort method, which uses mergesort
(O(nlgn)). So are you going to realize this when reading someones code
and you see:

sort(somelist);

That it's going to be horribly inefficient? Why shouldn't we strive for
a library where such things just don't compile?


I don't want to spend 2 hours browsing the ranges algorithms to figure
out how to combine them to remove an element...


You severely exaggerate the amount of time needed to browse the
algorithms. I wrote an equivalent in less than a minute. And I don't

std.container ranges

2011-10-30 Thread Max Wolter

Hello there.

I seem to be having problems wrapping my head around how to use the 
ranges in the context of containers in phobos. Specifically, I can't 
seem to figure out how to remove an element from a linked list.


 foreach(cell; organism)
 {
if(cell.x == x  cell.y == y)
{
   organism.stableLinearRemove(cell);
   break;
}
 }

mind.d(123): Error: function 
std.container.SList!(Cell).SList.linearRemove (Range r) is not callable 
using argument types (Cell)
mind.d(123): Error: cannot implicitly convert expression (cell) of type 
cell.Cell to Take!(Range)


I somehow get the feeling such a basic operation should just...work?

/Max


Re: std.container ranges

2011-10-30 Thread Max Wolter

On 10/30/2011 6:45 PM, Jonathan M Davis wrote:

On Sunday, October 30, 2011 11:38:30 Max Wolter wrote:

Hello there.

I seem to be having problems wrapping my head around how to use the
ranges in the context of containers in phobos. Specifically, I can't
seem to figure out how to remove an element from a linked list.

   foreach(cell; organism)
   {
  if(cell.x == x  cell.y == y)
  {
 organism.stableLinearRemove(cell);
 break;
  }
   }

mind.d(123): Error: function
std.container.SList!(Cell).SList.linearRemove (Range r) is not callable
using argument types (Cell)
mind.d(123): Error: cannot implicitly convert expression (cell) of type
cell.Cell to Take!(Range)

I somehow get the feeling such a basic operation should just...work?


linearRemove (and stableLinearRemove) takes a _range_ not a value. cell is an
element in the list, not a range over the list. The range that it takes must
be either of type SList.Range or Take!(SList.Range). You get that range by
slicing an SList. Take!(SList.Range) is for the case where you want only a
portion of the beginning of a range rather than the whole range. Your example
actually has a really simple solution:

auto found = find!((a){return a.x == x  a.y == y;})(organism[]);
organism.stableLinearRemove(take(found, 1));

It finds the element in the list that you're looking for, and then it passes a
range with that one element to stableLinearRemove so that it'll remove it.

- Jonathan M Davis


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.


/Max