L'utilisation de Random et OrderBy est-elle un bon algorithme de lecture aléatoire?

164

J'ai lu un article sur divers algorithmes de lecture aléatoire sur Coding Horror . J'ai vu que quelque part des gens ont fait ceci pour mélanger une liste:

var r = new Random();
var shuffled = ordered.OrderBy(x => r.Next());

Est-ce un bon algorithme de lecture aléatoire? Comment ça marche exactement? Est-ce une manière acceptable de faire cela?

Svish
la source

Réponses:

205

Ce n'est pas une façon de mélanger que j'aime, principalement parce que c'est O (n log n) sans raison valable quand il est facile d'implémenter un mélange O (n). Le code de la question "fonctionne" en donnant essentiellement un nombre aléatoire (espérons-le unique!) À chaque élément, puis en ordonnant les éléments en fonction de ce nombre.

Je préfère la variante de Durstenfield du shuffle Fisher-Yates qui échange des éléments.

La mise en œuvre d'une Shuffleméthode d'extension simple consisterait essentiellement à appeler ToListou ToArraysur l'entrée puis à utiliser une implémentation existante de Fisher-Yates. (Passez le Randomcomme paramètre pour rendre la vie généralement plus agréable.) Il y a beaucoup d'implémentations autour ... J'en ai probablement une dans une réponse quelque part.

La bonne chose à propos d'une telle méthode d'extension est qu'il serait alors très clair pour le lecteur ce que vous essayez réellement de faire.

EDIT: Voici une implémentation simple (pas de vérification d'erreur!):

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
    T[] elements = source.ToArray();
    // Note i > 0 to avoid final pointless iteration
    for (int i = elements.Length-1; i > 0; i--)
    {
        // Swap element "i" with a random earlier element it (or itself)
        int swapIndex = rng.Next(i + 1);
        T tmp = elements[i];
        elements[i] = elements[swapIndex];
        elements[swapIndex] = tmp;
    }
    // Lazily yield (avoiding aliasing issues etc)
    foreach (T element in elements)
    {
        yield return element;
    }
}

EDIT: Les commentaires sur les performances ci-dessous m'ont rappelé que nous pouvons réellement renvoyer les éléments lorsque nous les mélangeons:

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
    T[] elements = source.ToArray();
    for (int i = elements.Length - 1; i >= 0; i--)
    {
        // Swap element "i" with a random earlier element it (or itself)
        // ... except we don't really need to swap it fully, as we can
        // return it immediately, and afterwards it's irrelevant.
        int swapIndex = rng.Next(i + 1);
        yield return elements[swapIndex];
        elements[swapIndex] = elements[i];
    }
}

Cela ne fera plus que le travail nécessaire.

Notez que dans les deux cas, vous devez faire attention à l'instance que Randomvous utilisez comme:

  • La création de deux instances de Randomà peu près au même moment donnera la même séquence de nombres aléatoires (lorsqu'elle est utilisée de la même manière)
  • Random n'est pas thread-safe.

J'ai un articleRandom qui donne plus de détails sur ces problèmes et propose des solutions.

Jon Skeet
la source
5
Eh bien, des implémentations pour des choses petites, mais importantes, comme celle-ci, je dirais qu'il est toujours agréable de trouver ici sur StackOverflow. Alors oui s'il vous plaît, si vous voulez =)
Svish
9
Jon - votre explication de Fisher-Yates est équivalente à l'implémentation donnée dans la question (la version naïve). Durstenfeld / Knuth atteignent O (n) non pas par affectation, mais par sélection dans un ensemble décroissant et échange. De cette façon, le nombre aléatoire sélectionné peut se répéter et l'algorithme ne prend que O (n).
tvanfosson
8
Vous en avez probablement assez d'entendre parler de moi à ce sujet, mais j'ai rencontré un léger problème dans mes tests unitaires dont vous voudrez peut-être être conscient. Il y a une bizarrerie avec ElementAt qui fait qu'il appelle l'extension à chaque fois, ce qui donne des résultats peu fiables. Dans mes tests, je matérialise le résultat avant de vérifier pour éviter cela.
tvanfosson
3
@tvanfosson: Pas du tout malade :) Mais oui, les appelants doivent être conscients que c'est paresseusement évalué.
Jon Skeet
4
Un peu tard, mais veuillez noter source.ToArray();que vous devez avoir using System.Linq;dans le même fichier. Si vous ne le faites pas, vous obtenez cette erreur:'System.Collections.Generic.IEnumerable<T>' does not contain a definition for 'ToArray' and no extension method 'ToArray' accepting a first argument of type 'System.Collections.Generic.IEnumerable<T>' could be found (are you missing a using directive or an assembly reference?)
Powerlord
70

Ceci est basé sur la réponse de Jon Skeet .

Dans cette réponse, le tableau est mélangé, puis renvoyé en utilisant yield. Le résultat net est que le tableau est conservé en mémoire pendant la durée de foreach, ainsi que les objets nécessaires à l'itération, et pourtant le coût est tout au début - le rendement est fondamentalement une boucle vide.

Cet algorithme est beaucoup utilisé dans les jeux, où les trois premiers éléments sont choisis, et les autres ne seront nécessaires que plus tard, voire pas du tout. Ma suggestion concerne yieldles numéros dès qu'ils sont échangés. Cela réduira le coût de démarrage, tout en maintenant le coût d'itération à O (1) (essentiellement 5 opérations par itération). Le coût total resterait le même, mais le brassage lui-même serait plus rapide. Dans les cas où cela est appelé car collection.Shuffle().ToArray()cela ne fera théoriquement aucune différence, mais dans les cas d'utilisation mentionnés ci-dessus, cela accélérera le démarrage. En outre, cela rendrait l'algorithme utile dans les cas où vous n'avez besoin que de quelques éléments uniques. Par exemple, si vous devez retirer trois cartes d'un jeu de 52, vous pouvez appeler deck.Shuffle().Take(3)et seuls trois échanges auront lieu (bien que l'ensemble du tableau devrait d'abord être copié).

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
    T[] elements = source.ToArray();
    // Note i > 0 to avoid final pointless iteration
    for (int i = elements.Length - 1; i > 0; i--)
    {
        // Swap element "i" with a random earlier element it (or itself)
        int swapIndex = rng.Next(i + 1);
        yield return elements[swapIndex];
        elements[swapIndex] = elements[i];
        // we don't actually perform the swap, we can forget about the
        // swapped element because we already returned it.
    }

    // there is one item remaining that was not returned - we return it now
    yield return elements[0]; 
}
configurateur
la source
Aie! Cela ne renverra probablement pas tous les éléments de la source. Vous ne pouvez pas compter sur un nombre aléatoire unique pour N itérations.
P Daddy
2
Intelligent! (Et je déteste ce truc de 15 personnages ...)
Svish
@P Daddy: Hein? Voulez-vous élaborer?
Svish
1
Ou vous pouvez remplacer le> 0 par> = 0 et ne pas avoir à le faire (bien que, un coup RNG supplémentaire plus une affectation redondante)
FryGuy
4
Le coût de démarrage est O (N) comme le coût de source.ToArray ();
Dave Hillier
8

À partir de cette citation de Skeet:

Ce n'est pas une façon de mélanger que j'aime, principalement parce que c'est O (n log n) sans raison valable quand il est facile d'implémenter un mélange O (n). Le code de la question «fonctionne» en donnant essentiellement un numéro aléatoire ( espérons-le unique! ) À chaque élément, puis en ordonnant les éléments en fonction de ce nombre.

Je vais continuer à expliquer un peu la raison de l' unique, espérons-le!

Maintenant, à partir de Enumerable.OrderBy :

Cette méthode effectue un tri stable; c'est-à-dire que si les clés de deux éléments sont égales, l'ordre des éléments est conservé

C'est très important! Que se passe-t-il si deux éléments "reçoivent" le même nombre aléatoire? Il arrive qu'ils restent dans le même ordre qu'ils sont dans le tableau. Maintenant, quelle est la possibilité que cela se produise? Il est difficile de calculer exactement, mais il y a le problème d'anniversaire qui est exactement ce problème.

Maintenant, est-ce réel? Est-ce vrai?

Comme toujours, en cas de doute, écrivez quelques lignes de programme: http://pastebin.com/5CDnUxPG

Ce petit bloc de code mélange un tableau de 3 éléments un certain nombre de fois en utilisant l'algorithme de Fisher-Yates fait à l'envers, l'algorithme de Fisher-Yates fait en avant (dans la page wiki il y a deux algorithmes de pseudo-code ... Ils produisent l'équivalent résultats, mais l'un est fait du premier au dernier élément, tandis que l'autre est fait du dernier au premier élément), le mauvais algorithme naïf de http://blog.codinghorror.com/the-danger-of-naivete/ et en utilisant le .OrderBy(x => r.Next())et le .OrderBy(x => r.Next(someValue)).

Maintenant, Random.Next est

Entier signé 32 bits supérieur ou égal à 0 et inférieur à MaxValue.

donc c'est équivalent à

OrderBy(x => r.Next(int.MaxValue))

Pour tester si ce problème existe, nous pourrions agrandir le tableau (quelque chose de très lent) ou simplement réduire la valeur maximale du générateur de nombres aléatoires (ce int.MaxValuen'est pas un nombre "spécial" ... C'est simplement un très grand nombre). En fin de compte, si l'algorithme n'est pas biaisé par la stabilité du OrderBy, alors toute plage de valeurs devrait donner le même résultat.

Le programme teste ensuite certaines valeurs, comprises entre 1 et 4096. En regardant le résultat, il est assez clair que pour des valeurs faibles (<128), l'algorithme est très biaisé (4-8%). Avec 3 valeurs dont vous avez besoin au moins r.Next(1024). Si vous agrandissez le tableau (4 ou 5), cela r.Next(1024)ne suffit même pas. Je ne suis pas un expert en shuffling et en maths, mais je pense que pour chaque bit supplémentaire de longueur du tableau, vous avez besoin de 2 bits supplémentaires de valeur maximale (car le paradoxe d'anniversaire est connecté au sqrt (numvalues)), donc que si la valeur maximale est 2 ^ 31, je dirai que vous devriez pouvoir trier des tableaux jusqu'à 2 ^ 12/2 ^ 13 bits (4096-8192 éléments)

xanatos
la source
Bien énoncé, et affiche parfaitement un problème avec la question d'origine. Cela devrait être fusionné avec la réponse de Jon.
TheSoftwareJedi
6

C'est probablement correct dans la plupart des cas, et presque toujours, cela génère une distribution vraiment aléatoire (sauf lorsque Random.Next () produit deux entiers aléatoires identiques).

Il fonctionne en attribuant à chaque élément de la série un entier aléatoire, puis en ordonnant la séquence par ces entiers.

C'est totalement acceptable pour 99,9% des applications (sauf si vous devez absolument gérer le cas de bord ci-dessus). De plus, l'objection de skeet à son exécution est valide, donc si vous mélangez une longue liste, vous ne voudrez peut-être pas l'utiliser.

ripper234
la source
4

Cela s'est produit plusieurs fois auparavant. Recherchez Fisher-Yates sur StackOverflow.

Voici un exemple de code C # que j'ai écrit pour cet algorithme. Vous pouvez le paramétrer sur un autre type, si vous préférez.

static public class FisherYates
{
        //      Based on Java code from wikipedia:
        //      http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
        static public void Shuffle(int[] deck)
        {
                Random r = new Random();
                for (int n = deck.Length - 1; n > 0; --n)
                {
                        int k = r.Next(n+1);
                        int temp = deck[n];
                        deck[n] = deck[k];
                        deck[k] = temp;
                }
        }
}
Hughdbrown
la source
2
Vous ne devriez pas utiliser Randomcomme une variable statique comme celle-ci - Randomn'est pas thread-safe. Voir csharpindepth.com/Articles/Chapter12/Random.aspx
Jon Skeet
@Jon Skeet: bien sûr, c'est un argument légitime. OTOH, l'OP posait des questions sur un algorithme qui était tout à fait faux alors que c'est correct (autre que le cas d'utilisation du mélange de cartes multithread).
hughdbrown
1
Cela signifie simplement que c'est «moins faux» que l'approche du PO. Cela ne veut pas dire que c'est du code qui doit être utilisé sans comprendre qu'il ne peut pas être utilisé en toute sécurité dans un contexte multi-thread ... ce que vous n'avez pas mentionné. On s'attend à ce que les membres statiques puissent être utilisés en toute sécurité à partir de plusieurs threads.
Jon Skeet
@Jon Skeet: Bien sûr, je peux le changer. Terminé. J'ai tendance à penser que revenir à une question à laquelle on a répondu il y a trois ans et demi et dire: "C'est incorrect parce qu'il ne gère pas le cas d'utilisation multithread" alors que l'OP n'a jamais posé de questions de plus que l'algorithme est excessif. Passez en revue mes réponses au fil des ans. J'ai souvent donné des réponses aux PO qui allaient au-delà des exigences énoncées. J'ai été critiqué pour cela. Je ne m'attendrais pas à ce que les OP obtiennent des réponses adaptées à toutes les utilisations possibles.
hughdbrown
Je n'ai visité cette réponse que parce que quelqu'un d'autre m'a pointé dessus sur le chat. Bien que l'OP n'ait pas spécifiquement mentionné le threading, je pense qu'il vaut vraiment la peine de mentionner lorsqu'une méthode statique n'est pas thread-safe, car elle est inhabituelle et rend le code inadapté à de nombreuses situations sans modification. Votre nouveau code est thread-safe - mais toujours pas idéal car si vous l'appelez à partir de plusieurs threads "à peu près" en même temps pour mélanger deux collections de la même taille, les shuffles seront équivalents. Fondamentalement, Randomc'est une douleur à utiliser, comme indiqué dans mon article.
Jon Skeet
3

Cela semble être un bon algorithme de mélange, si vous n'êtes pas trop préoccupé par les performances. Le seul problème que je signalerais est que son comportement n'est pas contrôlable, vous pourriez donc avoir du mal à le tester.

Une option possible est d'avoir une graine à transmettre en tant que paramètre au générateur de nombres aléatoires (ou au générateur aléatoire en tant que paramètre), afin que vous puissiez avoir plus de contrôle et le tester plus facilement.

Samuel Carrijo
la source
3

J'ai trouvé la réponse de Jon Skeet entièrement satisfaisante, mais le robot-scanner de mon client signalera toute instance de Randomcomme un défaut de sécurité. Alors je l'ai échangé contre System.Security.Cryptography.RNGCryptoServiceProvider. En prime, il corrige ce problème de sécurité des threads qui a été mentionné. D'autre part, RNGCryptoServiceProvidera été mesuré comme 300 fois plus lent que l'utilisation Random.

Usage:

using (var rng = new RNGCryptoServiceProvider())
{
    var data = new byte[4];
    yourCollection = yourCollection.Shuffle(rng, data);
}

Méthode:

/// <summary>
/// Shuffles the elements of a sequence randomly.
/// </summary>
/// <param name="source">A sequence of values to shuffle.</param>
/// <param name="rng">An instance of a random number generator.</param>
/// <param name="data">A placeholder to generate random bytes into.</param>
/// <returns>A sequence whose elements are shuffled randomly.</returns>
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, RNGCryptoServiceProvider rng, byte[] data)
{
    var elements = source.ToArray();
    for (int i = elements.Length - 1; i >= 0; i--)
    {
        rng.GetBytes(data);
        var swapIndex = BitConverter.ToUInt32(data, 0) % (i + 1);
        yield return elements[swapIndex];
        elements[swapIndex] = elements[i];
    }
}
Frattaro
la source
3

Vous recherchez un algorithme? Vous pouvez utiliser ma ShuffleListclasse:

class ShuffleList<T> : List<T>
{
    public void Shuffle()
    {
        Random random = new Random();
        for (int count = Count; count > 0; count--)
        {
            int i = random.Next(count);
            Add(this[i]);
            RemoveAt(i);
        }
    }
}

Ensuite, utilisez-le comme ceci:

ShuffleList<int> list = new ShuffleList<int>();
// Add elements to your list.
list.Shuffle();

Comment ça marche?

Prenons une première liste triée des 5 premiers entiers: { 0, 1, 2, 3, 4 }.

La méthode commence par compter le nombre d'éléments et l'appelle count. Ensuite, en countdiminuant à chaque étape, il prend un nombre aléatoire entre 0et countet le déplace à la fin de la liste.

Dans l'exemple pas à pas suivant, les éléments pouvant être déplacés sont en italique , l'élément sélectionné est en gras :

0 1 2 3 4
0 1 2 3 4
0 1 2 4 3
0 1 2 4 3
1 2 4 3 0
1 2 4 3 0
1 2 3 0 4
1 2 3 0 4
2 3 0 4 1
2 3 0 4 1
3 0 4 1 2

SteeveDroz
la source
Ce n'est pas O (n). RemoveAt seul est O (n).
paparazzo
Hmm, vous avez raison, mon mauvais! Je vais supprimer cette partie.
SteeveDroz
1

Cet algorithme mélange en générant une nouvelle valeur aléatoire pour chaque valeur d'une liste, puis en ordonnant la liste en fonction de ces valeurs aléatoires. Considérez cela comme l'ajout d'une nouvelle colonne à une table en mémoire, puis en le remplissant avec des GUID, puis en le triant par cette colonne. Cela me semble être un moyen efficace (surtout avec le sucre lambda!)

Dave Swersky
la source
1

Un peu sans rapport, mais voici une méthode intéressante (qui même si elle est vraiment excessive, a VRAIMENT été implémentée) pour une génération vraiment aléatoire de lancers de dés!

Dice-O-Matic

La raison pour laquelle je publie ceci ici, c'est qu'il fait des remarques intéressantes sur la façon dont ses utilisateurs ont réagi à l'idée d'utiliser des algorithmes pour mélanger, sur de vrais dés. Bien sûr, dans le monde réel, une telle solution ne concerne que les extrémités vraiment extrêmes du spectre où le hasard a un si grand impact et peut-être que l'impact affecte l'argent;).

Irfy
la source
1

Je dirais que de nombreuses réponses ici comme "Cet algorithme mélange en générant une nouvelle valeur aléatoire pour chaque valeur d'une liste, puis en ordonnant la liste par ces valeurs aléatoires" pourraient être très erronées!

Je pense que cela n'attribue pas une valeur aléatoire à chaque élément de la collection source. Au lieu de cela, il pourrait y avoir un algorithme de tri fonctionnant comme Quicksort qui appellerait une fonction de comparaison environ n fois n log. Certains types d'algortihm s'attendent vraiment à ce que cette fonction de comparaison soit stable et renvoie toujours le même résultat!

Ne pourrait-il pas être que le IEnumerableSorter appelle une fonction de comparaison pour chaque étape de l'algorithme, par exemple quicksort et à chaque fois appelle la fonction x => r.Next()pour les deux paramètres sans les mettre en cache!

Dans ce cas, vous pourriez vraiment gâcher l'algorithme de tri et le rendre bien pire que les attentes sur lesquelles l'algorithme est construit. Bien sûr, il finira par devenir stable et retourner quelque chose.

Je pourrais le vérifier plus tard en mettant la sortie de débogage dans une nouvelle fonction "Next" pour voir ce qui se passe. Dans Reflector, je n'ai pas pu découvrir immédiatement comment cela fonctionne.

Christian
la source
1
Ce n'est pas le cas: le remplacement interne void ComputeKeys (éléments TElement [], nombre int); Type de déclaration: System.Linq.EnumerableSorter <TElement, TKey> Assembly: System.Core, Version = 3.5.0.0 Cette fonction crée d'abord un tableau avec toutes les clés qui consomment de la mémoire, avant que le tri rapide les trie
Christian
C'est bon à savoir - encore juste un détail d'implémentation cependant, qui pourrait éventuellement changer dans les versions futures!
Blorgbeard sort le
-5

Heure de démarrage pour exécuter sur le code avec effacer tous les threads et mettre en cache chaque nouveau test,

Premier code infructueux. Il fonctionne sur LINQPad. Si vous suivez pour tester ce code.

Stopwatch st = new Stopwatch();
st.Start();
var r = new Random();
List<string[]> list = new List<string[]>();
list.Add(new String[] {"1","X"});
list.Add(new String[] {"2","A"});
list.Add(new String[] {"3","B"});
list.Add(new String[] {"4","C"});
list.Add(new String[] {"5","D"});
list.Add(new String[] {"6","E"});

//list.OrderBy (l => r.Next()).Dump();
list.OrderBy (l => Guid.NewGuid()).Dump();
st.Stop();
Console.WriteLine(st.Elapsed.TotalMilliseconds);

list.OrderBy (x => r.Next ()) utilise 38,6528 ms

list.OrderBy (x => Guid.NewGuid ()) utilise 36,7634 ms (il est recommandé par MSDN.)

après la deuxième fois, les deux utilisent en même temps.

EDIT: TEST CODE sur Intel Core i7 [email protected], Ram 8 GB DDR3 @ 1600, HDD SATA 5200 rpm avec [Données: www.dropbox.com/s/pbtmh5s9lw285kp/data]

using System;
using System.Runtime;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Threading;

namespace Algorithm
{
    class Program
    {
        public static void Main(string[] args)
        {
            try {
                int i = 0;
                int limit = 10;
                var result = GetTestRandomSort(limit);
                foreach (var element in result) {
                    Console.WriteLine();
                    Console.WriteLine("time {0}: {1} ms", ++i, element);
                }
            } catch (Exception e) {
                Console.WriteLine(e.Message);
            } finally {
                Console.Write("Press any key to continue . . . ");
                Console.ReadKey(true);
            }
        }

        public static IEnumerable<double> GetTestRandomSort(int limit)
        {
            for (int i = 0; i < 5; i++) {
                string path = null, temp = null;
                Stopwatch st = null;
                StreamReader sr = null;
                int? count = null;
                List<string> list = null;
                Random r = null;

                GC.Collect();
                GC.WaitForPendingFinalizers();
                Thread.Sleep(5000);

                st = Stopwatch.StartNew();
                #region Import Input Data
                path = Environment.CurrentDirectory + "\\data";
                list = new List<string>();
                sr = new StreamReader(path);
                count = 0;
                while (count < limit && (temp = sr.ReadLine()) != null) {
//                  Console.WriteLine(temp);
                    list.Add(temp);
                    count++;
                }
                sr.Close();
                #endregion

//              Console.WriteLine("--------------Random--------------");
//              #region Sort by Random with OrderBy(random.Next())
//              r = new Random();
//              list = list.OrderBy(l => r.Next()).ToList();
//              #endregion

//              #region Sort by Random with OrderBy(Guid)
//              list = list.OrderBy(l => Guid.NewGuid()).ToList();
//              #endregion

//              #region Sort by Random with Parallel and OrderBy(random.Next())
//              r = new Random();
//              list = list.AsParallel().OrderBy(l => r.Next()).ToList();
//              #endregion

//              #region Sort by Random with Parallel OrderBy(Guid)
//              list = list.AsParallel().OrderBy(l => Guid.NewGuid()).ToList();
//              #endregion

//              #region Sort by Random with User-Defined Shuffle Method
//              r = new Random();
//              list = list.Shuffle(r).ToList();
//              #endregion

//              #region Sort by Random with Parallel User-Defined Shuffle Method
//              r = new Random();
//              list = list.AsParallel().Shuffle(r).ToList();
//              #endregion

                // Result
//              
                st.Stop();
                yield return st.Elapsed.TotalMilliseconds;
                foreach (var element in list) {
                Console.WriteLine(element);
            }
            }

        }
    }
}

Description du résultat: https://www.dropbox.com/s/9dw9wl259dfs04g/ResultDescription.PNG
Statistiques du résultat: https://www.dropbox.com/s/ewq5ybtsvesme4d/ResultStat.PNG

Conclusion:
Supposons: LINQ OrderBy (r.Next ()) et OrderBy (Guid.NewGuid ()) ne sont pas pires que la méthode de lecture aléatoire définie par l'utilisateur dans la première solution.

Réponse: Ce sont des contradictions.

GMzo
la source
1
La deuxième option n'est pas correcte et ses performances ne sont donc pas pertinentes . Cela ne répond toujours pas non plus à la question de savoir si la commande par un nombre aléatoire est acceptable, efficace ou comment cela fonctionne. La première solution a également des problèmes d'exactitude, mais ils ne sont pas aussi importants.
Servy le
Désolé, j'aimerais savoir quel est le meilleur type de paramètre de Quicksort de Linq OrderBy? J'ai besoin de tester les performances. Cependant, je pense que le type int a une vitesse meilleure que la chaîne de Guid, mais ce n'est pas le cas. J'ai compris pourquoi MSDN a recommandé. Les performances de la première solution modifiée sont identiques à celles de OrderBy avec une instance aléatoire.
GMzo
Quel est l'intérêt de mesurer les performances du code qui ne résout pas le problème? La performance n'est qu'une considération à faire entre deux solutions qui fonctionnent toutes les deux . Lorsque vous avez des solutions de travail, alors vous pouvez commencer à les comparer.
Servy le
Je dois avoir un temps pour tester sur plus de données puis si c'est fini, je promets de poster à nouveau. Supposons: je pense que Linq OrderBy n'est pas pire que la première solution. Opinion: C'est facile à utiliser et à comprendre.
GMzo
Il est nettement moins efficace que les algorithmes de brassage très simples et simples, mais encore une fois, les performances ne sont pas pertinentes . Ils ne mélangent pas les données de manière fiable, en plus d'être moins performants.
Servy