none
Mélanger un tableau d'entiers RRS feed

  • Question

  • Bonjour

    J'utilise le code suivant pour mélanger un tableau d'Integer :

        Dim LesUnités() As Integer = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
        Try
          'Shuffle(LesUnités)
          ShuffleArray(LesUnités)
          'Array.Sort(LesUnités, New Melangeur())
        Catch ex As ArgumentException
          MessageBox.Show(ex.Message)
        End Try
    
    Si j'exécute plusieurs fois le mélange, le PC ralentit considérablement je ne comprends pas pourquoi (ceci quel que soit la méthode utilisée)
    Private Shared ReadOnly _shuffleRnd As New Random()
      ' nécessaire pour la méthode ShuffleArray
      Public Shared Sub ShuffleArray(ByVal array As Integer())
        Dim arrayLength As Integer = array.Length
        ' parcours de la liste en partant de la fin
    
        For i As Integer = arrayLength - 1 To 2 Step -1
          ' tirage au sort d'un index entre 0 et la valeur courante de "i"
          Dim randomIndex As Integer = _shuffleRnd.[Next](i)
          ' intervertion des éléments situés aux index "i" et "randomIndex"
          Dim temp As Integer = array(i)
          array(i) = array(randomIndex)
          array(randomIndex) = temp
        Next
      End Sub
    
      Public Class Melangeur
        Implements System.Collections.IComparer
        Private Shared rnd As Random
        Shared Sub New()
          rnd = New Random()
        End Sub
    
        Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
          If Object.Equals(x, y) Then
            Return 0
          Else
            Return rnd.Next(-1, 1)
          End If
        End Function
      End Class
    
    Public Shared Function Shuffle(ByVal order As Integer()) As Integer()
        Dim rnd As Integer
        Dim val As Integer
        Dim max As Integer = (order.Length - 1)
    
        For i As Integer = 0 To max
          val = order(i)
          rnd = RndGen.Next(0, max + 1)
          order(i) = order(rnd)
          order(rnd) = val
        Next
    
        Return order
    
      End Function
    

    Y a-t-il un meilleur moyen de mélanger un array ?

    merci


    Cordialement
    Pascal
    http://www.scalpa.info
    lundi 2 mai 2011 17:09

Réponses

  • Bonjour

    Je ne déclare

     Public Shared RndGen As System.Random = New System.Random
    

    qu'au début de la classe.

    Puis dans chaque fonction où j'en ai besoin, je fais par exemple

    Public Shared Function GenNbreEntier(ByVal low As Integer, _ ByVal high As Integer) As Integer 
    
     Dim NbreTire As Integer 
    
    NbreTire = Int(RndGen.Next(low, high + 1)) 
    
    Return NbreTire 
    
    End Function
    
    Ce n'est pas la bonne méthode?
    Cordialement
    Pascal
    http://www.scalpa.info
    • Marqué comme réponse scalpa vendredi 6 mai 2011 07:02
    mercredi 4 mai 2011 12:09

Toutes les réponses

  • Si j'exécute plusieurs fois le mélange, le PC ralentit considérablement je ne comprends pas pourquoi (ceci quel que soit la méthode utilisée)

    Y a-t-il un meilleur moyen de mélanger un array ?

    Bonjour Pascal,

    Cette méthode là, un peu différente ne plante pas :

     

    Option Explicit On
    Public Class Form1
     Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
      Dim u(10) As Integer ' utilisation de 1 à 10
      Dim i As Integer
      Dim j As Integer
      For i = 1 To 10 ' 1er remplissage
       Randomize()
       u(i) = Int((9 - 0 + 1) * Rnd() + 0)
      Next i
    bis: ' fin remplissage si doublons
      For i = 1 To 10
       For j = 1 To 10
        If i <> j And u(i) = u(j) Then
         Randomize()
         u(j) = Int((9 - 0 + 1) * Rnd() + 0)
         GoTo bis
        End If
       Next j
      Next i
     End Sub
    End Class
    
    ' NOMBRE PSEUDO ALEATOIRES
     ' Nombre entiers entre maxi et mini avec un pas de 1
     Dim hasard As long
     Randomize
     hasard = Int((maxi - mini + 1) * Rnd + mini)
    

    Il y a plein de façons de piquer des nombres pseudo-aléatoires, par exemple du pompe le 1 sur les secondes, le 2 sur les 10eme, le 3, 4, 5 sur les millièmes depuis écoulés depuis le lancement du PC en espaçant de 2, le 6 tu multiplie les heures par les seconde et tu fais une division savante, etc...

    Cordialement.

    Joe.

     


    Joseph Attila PUSZTAY
    EhJoe       Logiciels       Romans       Ecrire



    • Modifié EhJoe mardi 3 mai 2011 12:28 3 modif code : désolé :o)
    • Proposé comme réponse EhJoe vendredi 6 mai 2011 07:04
    mardi 3 mai 2011 12:16
  •  

    Bonjour,

    Sur le MSDN il y a des exemples qui fonctionne sans aucun probleme de fonctionne et sans saturé la mémoire

    http://msdn.microsoft.com/fr-fr/library/system.random.aspx

     

    A bientot


    Cordialement,
    Xavier
    Alias Troxsa My M@iL
    mardi 3 mai 2011 13:11
    Auteur de réponse
  • De plus, si tu utilise le framework 4.0, il existe le Task Parallel Library qui permet d'accélérer ce genre de tâches.
    Microsoft MVP C# || gabrielmongeon.com || LinkedIn
    mardi 3 mai 2011 14:22
    Modérateur
  • Merci pour vos réponses. Je vais creuser la question... Peut-être que le ralentissement constaté vient d'ailleurs... Est-ce que l'appel répété d'une fonction est "RAM-ovore" par exemple ? faut-il coller un dispose() ou je ne sais quoi quelque part dans le code?

    Par exemple :

    ''' <summary>
      ''' Générateur d'une collection de nombres entiers, uniques ou non.
      ''' </summary>
      ''' <param name="Lower">borne inférieure du nombre</param>
      ''' <param name="Upper">borne supérieure du nombre</param>
      ''' <param name="HowMany">Combien de nombres?</param>
      ''' <param name="Unique">Les nombres sont-ils uniques?</param>
      ''' <returns>Une collection de nombres correspondant aux critères ci-dessus</returns>
      ''' <remarks>Générateur de nombres</remarks>
      Public Shared Function GenArrayNbresEntiers(ByVal Lower As Integer, _
                         ByVal Upper As Integer, _
                         Optional ByVal HowMany As Integer = 1, _
                         Optional ByVal Unique As Boolean = True) _
                         As List(Of Integer)
    
        Dim Result As New List(Of Integer)
    
        Do
          Dim Value = GenNbreEntier(Lower, Upper)
    
          If Not Unique OrElse Not Result.Contains(Value) Then
            Result.Add(Value)
          End If
        Loop Until Result.Count = HowMany
    
        Return Result
    
      End Function
    
    merci
    Cordialement
    Pascal
    http://www.scalpa.info
    mardi 3 mai 2011 15:16
  • Bonjour / soir

     

    Je ne pense pas que ça soit RAM-ovore car si on limite sont tableau cela reste quand même de petite taille en mémoire donc pas trop nécessaire de faire un dispose, cela finira dans le GC quand il sera appeler ...

     

    A bientot


    Cordialement,
    Xavier
    Alias Troxsa My M@iL
    mardi 3 mai 2011 20:01
    Auteur de réponse
  • Bonjour,

    la fonction Randomize() est utile pour initialiser la séquence de nombres aléatoires qui seront renvoyés par Rnd().

    (en utilisant l'horloge system comme "graine " pour la séquence)

    Vous ne devriez donc n'appeler qu'une seule fois cette fonction et ne pas l'appeler au sein des différentes boucles.

    Cordialement


    Edit : Effectivement cette remarque ne s'applique pas au code initiale mais aux autres possibilité ou l'on voit la fonction Randomize au sein des boucles

     

    mercredi 4 mai 2011 09:56
    Modérateur
  • Bonjour

    Je ne déclare

     Public Shared RndGen As System.Random = New System.Random
    

    qu'au début de la classe.

    Puis dans chaque fonction où j'en ai besoin, je fais par exemple

    Public Shared Function GenNbreEntier(ByVal low As Integer, _ ByVal high As Integer) As Integer 
    
     Dim NbreTire As Integer 
    
    NbreTire = Int(RndGen.Next(low, high + 1)) 
    
    Return NbreTire 
    
    End Function
    
    Ce n'est pas la bonne méthode?
    Cordialement
    Pascal
    http://www.scalpa.info
    • Marqué comme réponse scalpa vendredi 6 mai 2011 07:02
    mercredi 4 mai 2011 12:09
  • bonjour,

    La méthode est la bonne.

    Maintenant tout dépend du type utilser et de la valeur utiliser, là je vois que vous utilisez "integer"
    ce qu'il faut connaitre avant d'utiliser Integer c'est les valeur qu'il va recevoir, si les valeurs sont comprise entres -2 147 483 648 à 2 147 483 647 dans ce cas c'est bien ce qu'il faut utiliser et dans ce cas attention a la mémoire cela peux avoir un effet ...

    si ses valeurs sont trop grande il existe d'autre type plus petit et plus performant, je vous conseil d'aller voir sur le site MSDN, apres c'est a vous de faire l'algo pour que les valeurs entrer ne sorte pas du type sinon il y aura exception ...

     

    A bientot

     


    Cordialement,
    Xavier
    Alias Troxsa My M@iL
    mercredi 4 mai 2011 12:22
    Auteur de réponse