web-dev-qa-db-fra.com

Supprimer un élément d'un tableau régulier

J'ai un tableau d'objets Foo. Comment puis-je supprimer le deuxième élément du tableau?

J'ai besoin de quelque chose de similaire à RemoveAt() mais pour un tableau régulier.

107
leora

Si vous ne voulez pas utiliser List:

var foos = new List<Foo>(array);
foos.RemoveAt(index);
return foos.ToArray();

Vous pouvez essayer cette méthode d'extension que je n'ai pas encore testée:

public static T[] RemoveAt<T>(this T[] source, int index)
{
    T[] dest = new T[source.Length - 1];
    if( index > 0 )
        Array.Copy(source, 0, dest, 0, index);

    if( index < source.Length - 1 )
        Array.Copy(source, index + 1, dest, index, source.Length - index - 1);

    return dest;
}

Et utilisez-le comme:

Foo[] bar = GetFoos();
bar = bar.RemoveAt(2);
165
Andrew Kennan

La nature des tableaux est que leur longueur est immuable. Vous ne pouvez ajouter ou supprimer aucun des éléments du tableau.

Vous devrez créer un nouveau tableau d'un élément plus court et copier les anciens éléments dans le nouveau tableau, à l'exclusion de l'élément à supprimer.

Il est donc probablement préférable d’utiliser une liste plutôt qu’un tableau.

59
Sebastian Dietz

J'utilise cette méthode pour supprimer un élément d'un tableau d'objets. Dans ma situation, mes tableaux sont de petite longueur. Donc, si vous avez de grands tableaux, vous aurez peut-être besoin d'une autre solution.

private int[] RemoveIndices(int[] IndicesArray, int RemoveAt)
{
    int[] newIndicesArray = new int[IndicesArray.Length - 1];

    int i = 0;
    int j = 0;
    while (i < IndicesArray.Length)
    {
        if (i != RemoveAt)
        {
            newIndicesArray[j] = IndicesArray[i];
            j++;
        }

        i++;
    }

    return newIndicesArray;
}
48
EdHellyer

Solution linéaire LINQ:

myArray = myArray.Where((source, index) => index != 1).ToArray();

1 dans cet exemple correspond à l'index de l'élément à supprimer - dans cet exemple, pour la question d'origine, le deuxième élément (1 étant le deuxième élément de l'indexation de tableaux basée sur zéro C #).

Un exemple plus complet:

string[] myArray = { "a", "b", "c", "d", "e" };
int indexToRemove = 1;
myArray = myArray.Where((source, index) => index != indexToRemove).ToArray();

Après avoir exécuté cet extrait, la valeur de myArray sera { "a", "c", "d", "e" }.

42
Jon Schneider

C'est une façon de supprimer un élément de tableau, à partir de .Net 3.5, sans copier dans un autre tableau - en utilisant la même instance de tableau avec Array.Resize<T> :

public static void RemoveAt<T>(ref T[] arr, int index)
{
    for (int a = index; a < arr.Length - 1; a++)
    {
        // moving elements downwards, to fill the gap at [index]
        arr[a] = arr[a + 1];
    }
    // finally, let's decrement Array's size by one
    Array.Resize(ref arr, arr.Length - 1);
}
9
infografnet

Voici une ancienne version que j'ai qui fonctionne sur la version 1.0 du .NET framework et n'a pas besoin de types génériques.

public static Array RemoveAt(Array source, int index)
{
    if (source == null)
        throw new ArgumentNullException("source");

    if (0 > index || index >= source.Length)
        throw new ArgumentOutOfRangeException("index", index, "index is outside the bounds of source array");

    Array dest = Array.CreateInstance(source.GetType().GetElementType(), source.Length - 1);
    Array.Copy(source, 0, dest, 0, index);
    Array.Copy(source, index + 1, dest, index, source.Length - index - 1);

    return dest;
}

Ceci est utilisé comme ceci:

class Program
{
    static void Main(string[] args)
    {
        string[] x = new string[20];
        for (int i = 0; i < x.Length; i++)
            x[i] = (i+1).ToString();

        string[] y = (string[])MyArrayFunctions.RemoveAt(x, 3);

        for (int i = 0; i < y.Length; i++)
            Console.WriteLine(y[i]);
    }
}
5
Martin Brown

Ce n’est pas vraiment la façon de procéder, mais si la situation est triviale et que vous accordez de la valeur à votre temps, vous pouvez l’essayer pour les types nullables. 

Foos[index] = null

et plus tard, vérifiez les entrées nulles dans votre logique.

3
nawfal

Comme d'habitude, je suis en retard à la fête ...

J'aimerais ajouter une autre option à la liste des solutions de Nice déjà présente. =)
Je verrais cela comme une bonne opportunité pour les extensions.

Référence: http://msdn.Microsoft.com/en-us/library/bb311042.aspx

Nous définissons donc une classe statique et notre méthode.
Après cela, nous pouvons utiliser notre méthode étendue bon gré mal gré. =)

using System;

namespace FunctionTesting {

    // The class doesn't matter, as long as it's static
    public static class SomeRandomClassWhoseNameDoesntMatter {

        // Here's the actual method that extends arrays
        public static T[] RemoveAt<T>( this T[] oArray, int idx ) {
            T[] nArray = new T[oArray.Length - 1];
            for( int i = 0; i < nArray.Length; ++i ) {
                nArray[i] = ( i < idx ) ? oArray[i] : oArray[i + 1];
            }
            return nArray;
        }
    }

    // Sample usage...
    class Program {
        static void Main( string[] args ) {
            string[] myStrArray = { "Zero", "One", "Two", "Three" };
            Console.WriteLine( String.Join( " ", myStrArray ) );
            myStrArray = myStrArray.RemoveAt( 2 );
            Console.WriteLine( String.Join( " ", myStrArray ) );
            /* Output
             * "Zero One Two Three"
             * "Zero One Three"
             */

            int[] myIntArray = { 0, 1, 2, 3 };
            Console.WriteLine( String.Join( " ", myIntArray ) );
            myIntArray = myIntArray.RemoveAt( 2 );
            Console.WriteLine( String.Join( " ", myIntArray ) );
            /* Output
             * "0 1 2 3"
             * "0 1 3"
             */
        }
    }
}
2
Duncan
    private int[] removeFromArray(int[] array, int id)
    {
        int difference = 0, currentValue=0;
        //get new Array length
        for (int i=0; i<array.Length; i++)
        {
            if (array[i]==id)
            {
                difference += 1;
            }
        }
        //create new array
        int[] newArray = new int[array.Length-difference];
        for (int i = 0; i < array.Length; i++ )
        {
            if (array[i] != id)
            {
                newArray[currentValue] = array[i];
                currentValue += 1;
            }
        }

        return newArray;
    }
1
user2884232

Voici comment je l'ai fait ...

    public static ElementDefinitionImpl[] RemoveElementDefAt(
        ElementDefinition[] oldList,
        int removeIndex
    )
    {
        ElementDefinitionImpl[] newElementDefList = new ElementDefinitionImpl[ oldList.Length - 1 ];

        int offset = 0;
        for ( int index = 0; index < oldList.Length; index++ )
        {
            ElementDefinitionImpl elementDef = oldList[ index ] as ElementDefinitionImpl;
            if ( index == removeIndex )
            {
                //  This is the one we want to remove, so we won't copy it.  But 
                //  every subsequent elementDef will by shifted down by one.
                offset = -1;
            }
            else
            {
                newElementDefList[ index + offset ] = elementDef;
            }
        }
        return newElementDefList;
    }
1
Paul Mitchell

Dans un tableau normal, vous devez mélanger toutes les entrées de tableau supérieures à 2, puis le redimensionner à l'aide de la méthode Resize. Vous feriez peut-être mieux d'utiliser une liste de tableaux.

1
gkrogers

Je sais que cet article a dix ans et donc probablement mort, mais voici ce que j'essaierais de faire:

Utilisez la méthode IEnumerable.Skip (), trouvée dans System.Linq . Il va ignorer l'élément sélectionné du tableau et renvoyer une autre copie du tableau qui ne contient que tout sauf l'objet sélectionné. Ensuite, répétez-le pour chaque élément à supprimer, puis enregistrez-le dans une variable. 

Par exemple, si nous avons un tableau nommé "Sample" (de type int []) avec 5 nombres. Nous voulons supprimer le deuxième, essayez donc "Sample.Skip (2);" devrait renvoyer le même tableau sauf sans le 2e nombre.

0
commandertuna

Voici une petite collection de méthodes d’aide que j’ai produite à partir de certaines des réponses existantes. Il utilise à la fois des extensions et des méthodes statiques avec des paramètres de référence pour un maximum d’idéalité:

public static class Arr
{
    public static int IndexOf<TElement>(this TElement[] Source, TElement Element)
    {
        for (var i = 0; i < Source.Length; i++)
        {
            if (Source[i].Equals(Element))
                return i;
        }

        return -1;
    }

    public static TElement[] Add<TElement>(ref TElement[] Source, params TElement[] Elements)
    {
        var OldLength = Source.Length;
        Array.Resize(ref Source, OldLength + Elements.Length);

        for (int j = 0, Count = Elements.Length; j < Count; j++)
            Source[OldLength + j] = Elements[j];

        return Source;
    }

    public static TElement[] New<TElement>(params TElement[] Elements)
    {
        return Elements ?? new TElement[0];
    }

    public static void Remove<TElement>(ref TElement[] Source, params TElement[] Elements)
    {
        foreach (var i in Elements)
            RemoveAt(ref Source, Source.IndexOf(i));
    }

    public static void RemoveAt<TElement>(ref TElement[] Source, int Index)
    {
        var Result = new TElement[Source.Length - 1];

        if (Index > 0)
            Array.Copy(Source, 0, Result, 0, Index);

        if (Index < Source.Length - 1)
            Array.Copy(Source, Index + 1, Result, Index, Source.Length - Index - 1);

        Source = Result;
    }
}

Performance sage, il est décent, mais il pourrait probablement être amélioré. Remove s'appuie sur IndexOf et un nouveau tableau est créé pour chaque élément que vous souhaitez supprimer en appelant RemoveAt.

IndexOf est la seule méthode d'extension car il n'est pas nécessaire de renvoyer le tableau d'origine. New accepte plusieurs éléments d'un type quelconque pour produire un nouveau tableau de ce type. Toutes les autres méthodes doivent accepter le tableau d'origine en tant que référence, il n'est donc pas nécessaire d'affecter le résultat ultérieurement, car cela se produit déjà en interne.

J'aurais défini une méthode Merge pour fusionner deux tableaux; Cependant, cela peut déjà être accompli avec la méthode Add en transmettant un tableau réel au lieu de plusieurs éléments individuels. Par conséquent, Add peut être utilisé de deux manières pour joindre deux ensembles d’éléments:

Arr.Add<string>(ref myArray, "A", "B", "C");

Ou 

Arr.Add<string>(ref myArray, anotherArray);
0
James M