HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

"Breaking out" elements from an array

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
elementsarraybreakingfromout

Problem

I wrote a method that takes an array T[] array (T is a type parameter) and a second array int[] indices. The method should remove those entries from array, whose indices are stored in indices. Then, the resulting array will be "returned" as an out-parameter T[] rest. Finally, there is a second out parameter T[] removed that contains the removed items.

public static void RemoveViaIndex(this T[] array, int[] indices, out T[] rest, out T[] removed)
{
    int arrayLength = array.Length;
    int indicesLength = indices.Length;

    if (indicesLength == 0 || arrayLength == 0)
    {
        rest = array;
        removed = new T[0];
        return;
    }

    rest = new T[arrayLength - indicesLength];
    removed = new T[indicesLength];

    int copyBegin = 0;
    int copyEnd = -1;

    // We will only iterate over the index-array once
    // Therefore, the indices have to be in ascending order
    Array.Sort(indices);

    for (int indexForIndices = 0; indexForIndices < indicesLength; indexForIndices++)
    {
        // Copying elements in a chunk that ends at the 
        // next index that has to be removed
        copyEnd = indices[indexForIndices];
        Array.Copy(sourceArray: array, sourceIndex: copyBegin,
            destinationArray: rest, destinationIndex: copyBegin - indexForIndices, 
            length: copyEnd - copyBegin);
        removed[indexForIndices] = array[copyEnd];
        copyBegin = copyEnd + 1;
    }

    if (copyEnd < arrayLength - 1)
    {
        // Copy the final chunk that the loop did not take (if there is one)
        Array.Copy(array, copyBegin, rest, copyEnd - indicesLength + 1, arrayLength - copyBegin);
    }
}


I am assuming that all the indices in same-named array are valid indices for array. Are there any further border cases that I did not cover?

Furthermore, I wonder if this way is faster than an if statement that is contained within a for loop that iterates over the source array since the if-currentInd

Solution

So far my tests indicate that the performance is slightly better in the larger test cases because there is no hashing involved when accessing elements in deleteStatusArray. There are also no array copy operations.

public static void ZRemoveIndex(this T[] array, int[] indices, out T[] rest, out T[] removed)
{
    int arrayLength = array.Length;
    int indicesLength = indices.Length;

    if (indicesLength == 0 || arrayLength == 0)
    {
        rest = array;
        removed = new T[0];
        return;
    }

    rest = new T[arrayLength - indicesLength];
    removed = new T[indicesLength];
    //memo to remember which array indices are removed
    //all elements will be false by default
    var deleteStatusArray = new bool[array.Length];

    foreach (var removeIndex in indices)
    {
        //mark index that should be considered deleted
        deleteStatusArray[removeIndex] = true;
    }

    var notRemovedCounter = 0;
    var removedCounter = 0;
    for (int i = 0; i < array.Length; i++)
    {
        if(!deleteStatusArray[i])
            rest[notRemovedCounter++]= array[i];
        else
            removed[removedCounter++] = array[i];
    }
}

Code Snippets

public static void ZRemoveIndex<T>(this T[] array, int[] indices, out T[] rest, out T[] removed)
{
    int arrayLength = array.Length;
    int indicesLength = indices.Length;

    if (indicesLength == 0 || arrayLength == 0)
    {
        rest = array;
        removed = new T[0];
        return;
    }

    rest = new T[arrayLength - indicesLength];
    removed = new T[indicesLength];
    //memo to remember which array indices are removed
    //all elements will be false by default
    var deleteStatusArray = new bool[array.Length];

    foreach (var removeIndex in indices)
    {
        //mark index that should be considered deleted
        deleteStatusArray[removeIndex] = true;
    }

    var notRemovedCounter = 0;
    var removedCounter = 0;
    for (int i = 0; i < array.Length; i++)
    {
        if(!deleteStatusArray[i])
            rest[notRemovedCounter++]= array[i];
        else
            removed[removedCounter++] = array[i];
    }
}

Context

StackExchange Code Review Q#104938, answer score: 3

Revisions (0)

No revisions yet.