Jump to page: 1 2
Thread overview
Re: array idioms
Feb 25, 2011
Andrej Mitrovic
Feb 25, 2011
Jonathan M Davis
Feb 25, 2011
Jonathan M Davis
Feb 25, 2011
Andrej Mitrovic
Feb 25, 2011
Jonathan M Davis
Feb 25, 2011
Jonathan M Davis
Feb 25, 2011
Andrej Mitrovic
Feb 25, 2011
Jonathan M Davis
Feb 25, 2011
spir
Feb 25, 2011
Andrej Mitrovic
Feb 25, 2011
spir
Feb 28, 2011
Nick Treleaven
Feb 25, 2011
spir
February 25, 2011
On 2/25/11, spir <denis.spir@gmail.com> wrote:
> * delete an element in an associative array

Just use .remove?

void main()
{
    auto var = ["a" : 1];
    var.remove("b");    // nothing happens
    var.remove("a");    // "a" key is gone

    assert(!var.length);  // empty
}
February 25, 2011
On Friday, February 25, 2011 11:30:28 spir wrote:
> Hello,
> 
> What's the idiomatic way to:
> 
> * delete an element in an associative array

If you have the key, then just use remove. The online documentation for asseciative array discusses it. e.g.

b.remove("hello");

If you're looking to remove by value, however, you're going to have to figure out what its key is. And if you want to remove _all_ elements with the same value, then you're going to need to find _all_ of their keys. The best way to do that would probably just be to use a foreach loop:

foreach(k, v; aa)
{
    if(v == value)
        aa.remove(k);
}

I'm not sure if there are any problems with removing from an associative array while iterating over it though. I wouldn't think so, but I don't know so. Worst case though, you save the list of keys to remove and then remove them all once you have them all.

> * delete an element in a dyn array

I don't think that there is one right now. There should probably be a function in std.array which does what remove in std.container would do, but I don't believe that there's a function for it right now. So, the simplest way at the moment (albeit not the most efficient) would probably do to something like

auto found = findSplit(arr, value);
auto newArr = array(chain(found[0], found[2]));

The efficient way to do it, however, would involve shifting all of the elements in the array, which is more complicated and not the kind of code that you really want to be rewriting every time that you need to remove an element. But you _do_ need to remember that removing an arbitrary element from an array is _not_ cheap, because even in the most efficient case, that means moving a potentially large number of elements in the array - unlike a linked list where removal is cheap.

Of course, popFront and popBack would be the best way to remove from the ends of an array, and _that_ is efficient.

> * insert an element in a dyn array

Same as remove. There's no function for doing it at the moment. The best way at present would probably be to just concatenate the slices.

auto newArr = arr[0 .. i] ~ [value] ~ [i .. $];

But again, that's not particularly efficient. What you'd really want to do would be increase the size of the array by one, shift all of the elements after the insertion point over by one, and then set the element at the insertion point to the value that you're inserting. And of course, if appending to the array, ~= would be the best way to do it.

And again, inserting into arrays is _not_ efficient regardless, so if you're doing that sort of thing a lot, you probably should be using a different type of container.

- Jonathan M Davis
February 25, 2011
On Fri, 25 Feb 2011 15:09:44 -0500, Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> On Friday, February 25, 2011 11:30:28 spir wrote:
>> Hello,
>>
>> What's the idiomatic way to:
>>
>> * delete an element in an associative array
>
> If you have the key, then just use remove. The online documentation for
> asseciative array discusses it. e.g.
>
> b.remove("hello");
>
> If you're looking to remove by value, however, you're going to have to figure out
> what its key is. And if you want to remove _all_ elements with the same value,
> then you're going to need to find _all_ of their keys. The best way to do that
> would probably just be to use a foreach loop:
>
> foreach(k, v; aa)
> {
>     if(v == value)
>         aa.remove(k);
> }
>
> I'm not sure if there are any problems with removing from an associative array
> while iterating over it though. I wouldn't think so, but I don't know so. Worst
> case though, you save the list of keys to remove and then remove them all once
> you have them all.

It is illegal to remove from an AA you are iterating.  I've learned first hand that this causes subtle memory bugs.  Do not do this.

However, dcollections supports this idiom via the purge operation:

foreach(ref doPurge, v; &mymap.purge)
   doPurge = (v == value);

-Steve
February 25, 2011
On 2/25/11, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
>
>> * insert an element in a dyn array
>
> Same as remove. There's no function for doing it at the moment.

std.array.insert:

int[] a = [ 1, 2, 3, 4 ];
a.insert(2, [ 1, 2 ]);
assert(a == [ 1, 2, 1, 2, 3, 4 ]);

afaik insert was missing from the documentation in the last release (I've reported it), but now it's back in. So maybe that's why nobody knew about it.
February 25, 2011
On Friday 25 February 2011 12:16:19 Steven Schveighoffer wrote:
> On Fri, 25 Feb 2011 15:09:44 -0500, Jonathan M Davis <jmdavisProg@gmx.com>
> 
> wrote:
> > On Friday, February 25, 2011 11:30:28 spir wrote:
> >> Hello,
> >> 
> >> What's the idiomatic way to:
> >> 
> >> * delete an element in an associative array
> > 
> > If you have the key, then just use remove. The online documentation for asseciative array discusses it. e.g.
> > 
> > b.remove("hello");
> > 
> > If you're looking to remove by value, however, you're going to have to
> > figure out
> > what its key is. And if you want to remove _all_ elements with the same
> > value,
> > then you're going to need to find _all_ of their keys. The best way to
> > do that
> > would probably just be to use a foreach loop:
> > 
> > foreach(k, v; aa)
> > {
> > 
> >     if(v == value)
> > 
> >         aa.remove(k);
> > 
> > }
> > 
> > I'm not sure if there are any problems with removing from an associative
> > array
> > while iterating over it though. I wouldn't think so, but I don't know
> > so. Worst
> > case though, you save the list of keys to remove and then remove them
> > all once
> > you have them all.
> 
> It is illegal to remove from an AA you are iterating.  I've learned first hand that this causes subtle memory bugs.  Do not do this.

Good to know. I was wondering. It's simple enough though to just make a list of the keys to remove and then remove them afterwords.

- Jonathan M Davis
February 25, 2011
On Friday 25 February 2011 12:09:44 Jonathan M Davis wrote:
> On Friday, February 25, 2011 11:30:28 spir wrote:
> > * delete an element in a dyn array
> 
> I don't think that there is one right now. There should probably be a function in std.array which does what remove in std.container would do, but I don't believe that there's a function for it right now. So, the simplest way at the moment (albeit not the most efficient) would probably do to something like
> 
> auto found = findSplit(arr, value);
> auto newArr = array(chain(found[0], found[2]));
> 
> The efficient way to do it, however, would involve shifting all of the elements in the array, which is more complicated and not the kind of code that you really want to be rewriting every time that you need to remove an element. But you _do_ need to remember that removing an arbitrary element from an array is _not_ cheap, because even in the most efficient case, that means moving a potentially large number of elements in the array - unlike a linked list where removal is cheap.
> 
> Of course, popFront and popBack would be the best way to remove from the ends of an array, and _that_ is efficient.

Actually, on reflection, we probably _don't_ want a remove like std.container uses. What we probably want is something like remove and removeInPlace. The fact that dynamic arrays are really ranges rather than containers makes removing in place _far_ less desirable in many cases, and it's not necessarily a good idea to treat an array like a container in std.container.

- Jonathan M Davis
February 25, 2011
On Friday 25 February 2011 12:30:00 Andrej Mitrovic wrote:
> On 2/25/11, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
> >> * insert an element in a dyn array
> > 
> > Same as remove. There's no function for doing it at the moment.
> 
> std.array.insert:
> 
> int[] a = [ 1, 2, 3, 4 ];
> a.insert(2, [ 1, 2 ]);
> assert(a == [ 1, 2, 1, 2, 3, 4 ]);
> 
> afaik insert was missing from the documentation in the last release (I've reported it), but now it's back in. So maybe that's why nobody knew about it.

Ah. Good to know. Its not the sort of thing that I'm generally looking to do, however, so I don't tend to think about it. I don't believe that I've ever seen the function in the docs before, so that would explain why didn't know about it.

- Jonathan M Davis
February 25, 2011
I have asked for remove before, I got some responses here (in fact, Jonathan made an enhancement request for it):

http://www.digitalmars.com/d/archives/digitalmars/D/learn/Removing_an_object_from_a_range_23212.html

The topic was derailed, but essentially you can provide a predicate as a function literal to do the work:

import std.stdio;
import std.algorithm;

void main()
{
    int[] elements = [1, 2, 3, 2, 4];
    int needle = 2;

    elements = remove!((item) {return item == needle;} )(elements);
    assert(elements == [1, 3, 4]);
}
February 25, 2011
On Friday, February 25, 2011 12:51:53 Andrej Mitrovic wrote:
> I have asked for remove before, I got some responses here (in fact, Jonathan made an enhancement request for it):
> 
> http://www.digitalmars.com/d/archives/digitalmars/D/learn/Removing_an_objec t_from_a_range_23212.html
> 
> The topic was derailed, but essentially you can provide a predicate as a function literal to do the work:
> 
> import std.stdio;
> import std.algorithm;
> 
> void main()
> {
>     int[] elements = [1, 2, 3, 2, 4];
>     int needle = 2;
> 
>     elements = remove!((item) {return item == needle;} )(elements);
>     assert(elements == [1, 3, 4]);
> }

Actually, you can probably just use replace and give it an empty range for the third argument. Still, there should probably be a function in std.array which removes a value from an array based on its value. A function that's essentially identical to the version of replace which takes two ranges in addition to the array but doesn't take the range to replace with would probably do the trick:

R1 replace(R1, R2)(R1 subject,  R2 toRemove) if(...) {...}

- Jonathan M Davis
February 25, 2011
On 02/25/2011 08:55 PM, Andrej Mitrovic wrote:
> On 2/25/11, spir<denis.spir@gmail.com>  wrote:
>> * delete an element in an associative array
>
> Just use .remove?
>
> void main()
> {
>      auto var = ["a" : 1];
>      var.remove("b");    // nothing happens
>      var.remove("a");    // "a" key is gone
>
>      assert(!var.length);  // empty
> }

Sh*t, I have missed it. Sorry for the no*se. But where is this func implemented? I could not find it by browsing. (It's also not in object.d, apparently; while usually when I cannot find something, it's hidden in there ;-)

Denis
-- 
_________________
vita es estrany
spir.wikidot.com

« First   ‹ Prev
1 2