61 votes

C # moyen le plus rapide de changer de tableau

Comment puis-je déplacer rapidement tous les éléments d'un tableau vers la gauche, en remplissant la fin avec null?

Par exemple, [0,1,2,3,4,5,6] deviendrait [1,2,3,4,5,6, null]

Edit: J'ai dit rapidement mais je suppose que je voulais dire efficacement. Je dois le faire sans créer une liste ou une autre structure de données. C’est quelque chose que je dois faire plusieurs centaines de milliers de fois en un laps de temps aussi court que possible.

114voto

Jason Punyon Points 21244

Voici mon harnais de test ...

 var source = Enumerable.Range(1, 100).Cast<int?>().ToArray();
var destination = new int?[source.Length];

var s = new Stopwatch();
s.Start();
for (int i = 0; i < 1000000;i++)
{
    Array.Copy(source, 1, destination, 0, source.Length - 1);
}
s.Stop();
Console.WriteLine(s.Elapsed);
 

Voici les résultats de performance pour 1 million d'itérations de chaque solution (Intel Core 8 Xeon E5450 à 3,00 GHz)

                        100 elements  10000 elements
For Loop                     0.390s         31.839s 
Array.Copy()                 0.177s         12.496s
Aaron 1                      3.789s         84.082s
Array.ConstrainedCopy()      0.197s         17.658s
 

Faites le choix pour vous-même :)

63voto

Ben M Points 14458

La plus rapide façon de le faire est d'utiliser Array.Copy, ce qui, dans le final de la mise en œuvre utilise une mémoire de masse opération de transfert (similaire à memcpy):

var oldArray = new int?[] { 1, 2, 3, 4, 5, 6 };
var newArray = new int?[oldArray.Length];
Array.Copy(oldArray, 1, newArray, 0, oldArray.Length - 1);
// newArray is now { 2, 3, 4, 5, 6, null }

Modifié: selon la documentation:

Si sourceArray et destinationArray se chevauchent, cette méthode se comporte comme si les valeurs d'origine de sourceArray ont été conservés dans un emplacement temporaire avant de destinationArray est écrasé.

Donc, si vous ne voulez pas allouer un nouveau tableau, vous pouvez passer dans le tableau d'origine pour à la fois la source et la destination, bien que j'imagine que le compromis sera un peu plus lent de la performance car les valeurs de passer par un hébergement temporaire position.

Je suppose que, comme dans toute enquête de ce genre, vous devriez faire un peu rapide de l'analyse comparative.

13voto

tdaines Points 381

Voici ma solution, similaire à celle de Task dans la mesure où il s’agit d’un simple wrapper Array et du temps nécessaire à O (1) pour déplacer le tableau vers la gauche.

 public class ShiftyArray<T>
{
    private readonly T[] array;
    private int front;

    public ShiftyArray(T[] array)
    {
        this.array = array;
        front = 0;
    }

    public void ShiftLeft()
    {
        array[front++] = default(T);
        if(front > array.Length - 1)
        {
            front = 0;
        }
    }

    public void ShiftLeft(int count)
    {
        for(int i = 0; i < count; i++)
        {
            ShiftLeft();
        }
    }

    public T this[int index]
    {
        get
        {
            if(index > array.Length - 1)
            {
                throw new IndexOutOfRangeException();
            }

            return array[(front + index) % array.Length];
        }
    }

    public int Length { get { return array.Length; } }
}
 

Lancer le code de test de Jason Punyon ...

 int?[] intData = Enumerable.Range(1, 100).Cast<int?>().ToArray();
ShiftyArray<int?> array = new ShiftyArray<int?>(intData);

Stopwatch watch = new Stopwatch();
watch.Start();

for(int i = 0; i < 1000000; i++)
{
    array.ShiftLeft();
}

watch.Stop();

Console.WriteLine(watch.ElapsedMilliseconds);
 

Prend ~ 29ms, quelle que soit la taille de la matrice.

9voto

Andrey Points 36869

il suffit de faire:

 int?[] newAr = new int?[oldAr.Length];
for (int i = 1; i < oldAr.Length; i++)
   newAr[i - 1] = oldAr[i];
 

9voto

Seb Points 2117

Ne pourriez-vous pas utiliser System.Collections.Generic.Queue au lieu d'un tableau?

Je pense que vous devez effectuer des actions sur votre valeur, de la supprimer, utiliser une file d'attente semble donc plus approprié:

 // dummy initialization
        System.Collections.Generic.Queue<int> queue = new Queue<int>();
        for (int i = 0; i < 7; ++i ) { queue.Enqueue(i); }// add each element at the end of the container

        // working thread
        if (queue.Count > 0)
            doSomething(queue.Dequeue());// removes the last element of the container and calls doSomething on it
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X