Jump to page: 1 2
Thread overview
Remove array element within function
Jul 05, 2021
Rekel
Jul 05, 2021
Mike Parker
Jul 05, 2021
Mike Parker
Jul 05, 2021
Rekel
Jul 05, 2021
Rekel
Jul 05, 2021
Mike Parker
Jul 05, 2021
Mike Parker
Jul 05, 2021
Mike Parker
Jul 05, 2021
Rekel
Jul 05, 2021
jfondren
Jul 05, 2021
Rekel
Jul 05, 2021
Ali Çehreli
July 05, 2021

Is there an easy way to remove elements from an array passed in as a parameter?

Every example I find does something along the lines of:

int[] a = ...
long index = countUntil(a, element);
a = a.remove(index);

But what do you do when you have?:

void function(int[] a){
    . . .
    long index = countUntil(a, element);
    a.remove(index);
}

I assume I can't use a=a.remove(index), as I'm guessing this will only change the array inside the function itself, not the array that's actually used to call the function.

Am I the only one slightly unamused by how arrays/ranges work? They keep backfiring on me, or require weird additions other languages wouldn't require such as manually changing .length, or worrying about what operation returns a copy etc. (Kind of jealous of java's ease here)

July 05, 2021

On Monday, 5 July 2021 at 13:10:55 UTC, Rekel wrote:

>

But what do you do when you have?:
```d
void function(int[] a){
    . . .
    long index = countUntil(a, element);
    a.remove(index);
}
```

void function(ref int[] a) {
    ...
}

An array is effectively a length/pointer pair that you are passing by value. If you want to do anything that affects either property, you need to pass by ref.

July 05, 2021

On Monday, 5 July 2021 at 13:10:55 UTC, Rekel wrote:

>

Am I the only one slightly unamused by how arrays/ranges work? They keep backfiring on me, or require weird additions other languages wouldn't require such as manually changing .length, or worrying about what operation returns a copy etc. (Kind of jealous of java's ease here)

D's arrays are friggin' awesome. I don't think they're any more difficult than in Java.

In what situations do you need to manually change the length? Where do you worry about copies? It's possible there's something you're overlooking.

July 05, 2021

Ah, ref, thanks, I didn't know if that would work as I was confused since arrays themselves are kind of already pointers.

On Monday, 5 July 2021 at 13:18:55 UTC, Mike Parker wrote:

>

In what situations do you need to manually change the length? Where do you worry about copies? It's possible there's something you're overlooking.

I believe for setting length it was both when I wanted to initialize the array to a certain length (instead of having that inline with the declaration) & when I want to clear the array of all data. Though I also found threads in which people mentioned changing the length manually after calling remove.

The copies were mostly at play in scenarios such as this one, but also when I'm appending lists to lists, in a list.addAll(list2); scenario. Though I guess I'm just not used to reassigning on the list variable after doing things with it.

Also, is my use of long correct? The documentation wasn't very clear on the return type of remove, just calling it a 'number'.

Again thanks for your help 😅

July 05, 2021

I'm not sure if this is the place to talk about it, but on the same topic it's a little strange to me neither the Dlang Tour nor the arrays spec page mention removing elements. Even though basically everyone is going to use it sooner or later (most likely sooner).

Is that because it's part of the library? That's the only reason I could think of, while in a way I could make that argument for appending in the case it hadn't been given the ~ and ~= operators.

July 05, 2021

On Monday, 5 July 2021 at 13:10:55 UTC, Rekel wrote:

>

Am I the only one slightly unamused by how arrays/ranges work? They keep backfiring on me, or require weird additions other languages wouldn't require such as manually changing .length, or worrying about what operation returns a copy etc. (Kind of jealous of java's ease here)

It's easy to start to learn about D's dynamic arrays and ranges and then welcome them as false friends. They're genuinely great, but they're not quite the same thing as what you recognized them as, and as long as this confusion persists, frustration will occur. You were probably expecting dynamic arrays to work like a class:

import std.array, std.algorithm;

class Array {
    int[] data;
    this(int[] xs) { data = xs; }
}

void removeEvens(Array a) {
    a.data = a.data.filter!"a%2".array;
}

unittest {
    auto h = new Array([1, 2, 4, 5]);
    h.removeEvens;
    assert(h.data == [1, 5]);
}

removeEvens gets a reference to a thing, it mutates it, job done.

An int[] parameter though is a copy of a slice. It's more like like this struct:

import std.array, std.algorithm;

struct Array {
    int* data;
    size_t length;
    this(int[] xs) { data = xs.ptr; length = xs.length; }
}

void removeEvens(Array a) {
    for (size_t i = 0; i < a.length; ++i) {
        if (a.data[i] % 2 == 0) {
            a.data[0 .. a.length].remove!(SwapStrategy.stable)(i);
            a.length--;
            i--; // !
        }
    }
}

unittest {
    auto h = Array([1, 2, 4, 5]);
    h.removeEvens;
    assert(h.data[0 .. h.length] == [1, 5, 5, 5]);
}

before removeEvens exits, its copy of a has become the intended 2-length array with only odd elements, but that copy is thrown away and the original 4-length array just sees its memory changed to have a 2-array prefix of its old odd elements, and then it has a suffix of garbage.

Of ranges, they look like visual pipelines of functions that directly alter data that flows through them, but their actual result is the pipeline and not the data. Range functions take shorter bits of pipeline as an argument and produce longer bits of pipeline as a result, and their errors are all pipeline related: "I only connect to sorted ranges", "I only connect to randomly-accessible ranges", etc.

On Monday, 5 July 2021 at 13:34:50 UTC, Rekel wrote:

>

Also, is my use of long correct? The documentation wasn't very clear on the return type of remove, just calling it a 'number'.

What use of long?

remove returns the same type of range as it gets:

Range remove(SwapStrategy s = SwapStrategy.stable, Range, Offset...)(Range range, Offset offset)
^^^^^                                              ^^^^^             ^^^^^

The first Range is the return type, the second Range is a template type parameter, and the third Range is the argument type. When you remove from an int[] you're calling a specialized function that returns an int[]

July 05, 2021

On Monday, 5 July 2021 at 13:34:50 UTC, Rekel wrote:

>

Ah, ref, thanks, I didn't know if that would work as I was confused since arrays themselves are kind of already pointers.

Except they're not :-) Think of them as struct instances with length and pointer fields. That's actually what they are.

>

I believe for setting length it was both when I wanted to initialize the array to a certain length (instead of having that inline with the declaration)

int[] arr;
arr = new int[](100);
>

& when I want to clear the array of all data. Though I also found threads in which people mentioned changing the length manually after calling remove.

You shouldn't need to adjust the length after remove as long as you assign the return value to the original array. And actually, I didn't pay close enough attention to your original function. You didn't do that. It should be:

void removeItem(ref int[] a){
    ...
    a = a.remove(index);
}

Or this:

int[] removeElement(int[] a) {
    ...
    return a.remove(index);
}

// Later
elems = removeElement(elems);
>

The copies were mostly at play in scenarios such as this one, but also when I'm appending lists to lists, in a list.addAll(list2); scenario. Though I guess I'm just not used to reassigning on the list variable after doing things with it.

You never copy the contents of a dynamic array/slice. That only comes into play with static arrays:

void someFunc1(int[3] a) {}
void someFunc2(int[] a);

int[3] a = [1, 2, 3];
someFunc1(a);    // This copies all the elements
someFunc2(a);    // This implicitly slices the array

Here are some resources that may help:

https://ddili.org/ders/d.en/arrays.html
https://ddili.org/ders/d.en/slices.html
https://dlang.org/articles/d-array-article.html
https://dlang.org/blog/2017/03/20/dont-fear-the-reaper/

Pay particular attention to the append operator + reserve. That plus the ability to slice without copying is where the real power of D's arrays lies. Then look into std.array.Appender when you have lots of items to append:

https://dlang.org/phobos/std_array.html#Appender

>

Also, is my use of long correct? The documentation wasn't very clear on the return type of remove, just calling it a 'number'.

If you look in the function signature, it returns ptrdiff_t:

https://dlang.org/phobos/std_algorithm_searching.html#countUntil

Which is defined in object.d:

https://github.com/dlang/druntime/blob/master/src/object.d#L61

It's long on 64-bit systems and int on 32-bit. So you can use ptrdiff_t or just auto:

auto index = countUntil(...);
>

Again thanks for your help 😅

That's why we're here :-)

July 05, 2021

On Monday, 5 July 2021 at 13:41:59 UTC, Rekel wrote:

>

I'm not sure if this is the place to talk about it, but on the same topic it's a little strange to me neither the Dlang Tour nor the arrays spec page mention removing elements. Even though basically everyone is going to use it sooner or later (most likely sooner).

Is that because it's part of the library? That's the only reason I could think of, while in a way I could make that argument for appending in the case it hadn't been given the ~ and ~= operators.

I had no involvement in creating the Tour, so I could only guess why it isn't covered. But if you think it should be, you can always submit an issue:

https://github.com/dlang-tour/core/issues

July 05, 2021

On Monday, 5 July 2021 at 14:30:11 UTC, Mike Parker wrote:

>

You never copy the contents of a dynamic array/slice. That only comes into play with static arrays:

I should rephrase that. You aren't going to copy the contents of an array/slice just by passing it to a function.

July 05, 2021

On Monday, 5 July 2021 at 14:22:24 UTC, jfondren wrote:

>

What use of long?

remove returns the same type of range as it gets:

My apology, I meant to say countUntil instead of remove in that context.

« First   ‹ Prev
1 2