none
numeri random RRS feed

  • Domanda

  • Salve a tutti un'altra domanda per voi:

    vorrei generare un numero random che da un valore minimo ad un valore massimo mi estraesse un mumero e fin qui nessun problema:

     Dim x As New Random
            Dim y As Integer
            y = x.Next(20, 50)

    vorrei pero' escudere ad ogni estrazione successiva il numero estratto. quindi supponiamo, nell'esempio, sia uscito il n°22

    quindi dal renge 20 50 sia escuso il 22 e cosi via fino alla fine dei numeri, come una tombola in sostanza

    Grazie in anticipo Daniele

    martedì 12 febbraio 2013 18:48

Risposte

  • Hello Daniele1970,

    ti propongo la mia implementazione basata su LINQ.

    Public Function EstraiNumero(min As Integer, max As Integer, estratti As IEnumerable(Of Integer)) As Integer
       If estratti is nothing then throw new ArgumentNullException() 
       If max <= min Then Throw New ArgumentException()
       ' Creo l'oggetto per l'estrazione dei numeri casuali
       Dim rnd As New Random(DateTime.Now.Millisecond)
       ' Recupero i numeri non ancora estratti
       Dim numNonEstratti = Enumerable.Range(min, max - min + 1).Where(Function(a) Not estratti.Contains(a))
       ' Recupero il numero casuale tra quelli non estratti
       Dim number = numNonEstratti.Skip(rnd.Next(numNonEstratti.Count)).Take(1).First()
       Return number
    End Function

    min e max sono gli estremi del range tra cui estrarre, mentre estratti è
    la lista dei numeri già estratti.
    Lo puoi utilizzare nel seguente modo:
     
    Dim listaNumeri = New List(Of Integer)
    Dim min = 20
    Dim max = 100
    For index = 1 To max - min + 1
       Dim num = EstraiNumero(min, max, listaNumeri)
       Console.WriteLine(index.ToString() + " : " + num.ToString())
       listaNumeri.Add(num)
    Next

     
     

    mercoledì 13 febbraio 2013 15:49
    Moderatore

Tutte le risposte

  • Ciao,

    ti suggerisco questo simpatico video tutorial:

    http://www.youtube.com/watch?v=VP8lKxQa3CY

    http://www.youtube.com/watch?v=aG-S6jD3Bsc

    Anche se si parla di una tombola alla fine il concetto è riutilizzabile nel tuo caso!

    Un saluto

    Ruggiero


    Ruggiero Lovreglio
    www.ruggierolovreglio.altervista.org


    martedì 12 febbraio 2013 19:07
  • Ciao Daniele1970,

    Salve a tutti un'altra domanda per voi:

    vorrei generare un numero random che da un valore minimo ad un valore massimo mi estraesse un mumero e fin qui nessun problema:

     Dim x As New Random
            Dim y As Integer
            y = x.Next(20, 50)

    vorrei pero' escudere ad ogni estrazione successiva il numero estratto. quindi supponiamo, nell'esempio, sia uscito il n°22

    quindi dal renge 20 50 sia escuso il 22 e cosi via fino alla fine dei numeri, come una tombola in sostanza

    Grazie in anticipo Daniele

    quello che e possibile fare e per prima cosa creare una collection di tipo integer che contiene la quantità di numeri desiderata , dopo di che leggi mediante il metodo Next della Classe Random il valore ed esegui un confronto nella collection che hai creato precedentemente , il tutto mediante il metodo Contains , quest'ultimo verifica se il valore che passi come argomento e presente all'interno della collection , se esiste lo rimuovi mediante il metodo Remove e passi come argomento il numero da togliere quindi il numero estratto , per meglio spiegare vedi esempio seguente.

        ReadOnly _firstvalue As New List(Of Integer)
        ReadOnly _random As New Random
        Dim _value As Integer
    

        Private Sub Button1Click(sender As Object, e As EventArgs) Handles Button1.Click
            'estrai un numero
            _value = _random.Next(20, 50)
    
            'qui e solo per comodità , leggi il numero estratto
            TextBox1.Text = _value.ToString()
    
            'qui esegui il confronto mediante il metodo Contains
            If (_firstvalue.Contains(_value)) Then
                MessageBox.Show(String.Concat("il numero", _value.ToString(), " estato rimosso."))
                'rimuovi il numero estratto dalla collection
                _firstvalue.Remove(_value)
    
                'visualizzi i numeri rimesti all'interno della collection
                Dim numeririmanenti As Integer = _firstvalue.Count - 1
                TextBox2.Text = numeririmanenti.ToString()
                Exit Sub
            End If
        End Sub
    
        Private Sub Button2Click(sender As Object, e As EventArgs) Handles Button2.Click
            'popoli la collection con i numeri desiderati
            For i As Integer = 20 To 50
                _firstvalue.Add(i)
            Next
            TextBox2.Text = _firstvalue.Count.ToString()
        End Sub

    Le textbox sono semplicemente di sola visualizzazione.

    Ciao.


    martedì 12 febbraio 2013 19:42
  • blic Class Form1
        Dim Estratti As List(Of Integer)
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim Num As New Random
            Dim y As Integer
            y = Num.Next(20, 50)
            For i = 0 To Estratti.Count - 1
                y = Num.Next(20, 50)
            Next
            MsgBox("Numero estratto: " & y)
        End Sub
    End Class

    Semplice semplice!

    Qui la spiegazione:

    blic Class Form1
        'Creo una lista dove inserirò tutti i numeri estratti
        Dim Estratti As List(Of Integer)
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            'Creo un numero a caso
            Dim Num As New Random
            Dim y As Integer
            y = Num.Next(20, 50)
            'Controllo ogni singolo numero esistente in        "Estratti"
            For i = 0 To Estratti.Count - 1
               'Finchè non trovo un numero non estratto, continuo a cercare...
                y = Num.Next(20, 50)
            Next
            'Visualizzo il numero estratto
            MsgBox("Numero estratto: " & y)
        End Sub
    End Class

    mercoledì 13 febbraio 2013 14:02
  • Hello Daniele1970,

    ti propongo la mia implementazione basata su LINQ.

    Public Function EstraiNumero(min As Integer, max As Integer, estratti As IEnumerable(Of Integer)) As Integer
       If estratti is nothing then throw new ArgumentNullException() 
       If max <= min Then Throw New ArgumentException()
       ' Creo l'oggetto per l'estrazione dei numeri casuali
       Dim rnd As New Random(DateTime.Now.Millisecond)
       ' Recupero i numeri non ancora estratti
       Dim numNonEstratti = Enumerable.Range(min, max - min + 1).Where(Function(a) Not estratti.Contains(a))
       ' Recupero il numero casuale tra quelli non estratti
       Dim number = numNonEstratti.Skip(rnd.Next(numNonEstratti.Count)).Take(1).First()
       Return number
    End Function

    min e max sono gli estremi del range tra cui estrarre, mentre estratti è
    la lista dei numeri già estratti.
    Lo puoi utilizzare nel seguente modo:
     
    Dim listaNumeri = New List(Of Integer)
    Dim min = 20
    Dim max = 100
    For index = 1 To max - min + 1
       Dim num = EstraiNumero(min, max, listaNumeri)
       Console.WriteLine(index.ToString() + " : " + num.ToString())
       listaNumeri.Add(num)
    Next

     
     

    mercoledì 13 febbraio 2013 15:49
    Moderatore
  • Hello Helroos,
    il tuo codice, probabilmente, va in errore e, ad occhio e croce, non fa quello
    che dice.
    Va in errore perchè, nonostante tu commenti con "creo la lista in cui inserirò.....",
    in realtà la lista non viene mai creata e, quindi, ti prendi una bella eccezione
    nel momento in cui chiami Estratti.Count
    Non fa quello che dice perchè, anche se non andasse in errore, non c'è alcun
    confronto con i numeri nella lista Estratti e, d'altronde, nessuno aggiunge
    numeri alla lista, quindi non vedo come potrebbe eseguire il "controllo ogni
    singolo numero esistente....".
     
     
    mercoledì 13 febbraio 2013 15:55
    Moderatore
  • Per ora grazie a tutti ma nessuno dei codici finora provati riesce a fare quello che volevo

    ho anche visto il video suggerito da Ruggero ma anche quello purtroppo restituisce un'eccezione alla fine del ciclo.

    Daniele

    mercoledì 13 febbraio 2013 16:57
  • Ciao Daniele, vedi se gradisci questo

    Public Class Form7
        'definisce il range dei numeri
        Dim dal As Integer = 59
        Dim al As Integer = 64
        'memoria dei numeri estratti
        Dim p As String = StrDup(al - dal + 1, "-")
        Private Sub Form7_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            'evita che si presenti la stessa sequenza pseudocasuale
            Randomize(Now.Millisecond)
        End Sub
    
        Sub reset()
            'reset
            p = StrDup(al - dal + 1, "-")
        End Sub
    
        Function EstraiACaso() As Integer
            Dim x As Integer
    
            'controlla che l'urna non sia vuota
            'altrimenti avvisa
            If p = StrDup(al - dal + 1, "+") Then
                MsgBox("Numeri finiti")
                Return -1
            End If
    
            'sceglie un numero a caso
            x = Rnd(1) * (al - dal) + dal
    
            'se il numero scelto è stato già estratto cicla 
            'fino a trovarne uno non estratto
            Do While p.Substring(x - dal, 1) = "+"
                x = Rnd(1) * (al - dal) + dal
            Loop
    
            'segna il numero come estratto
            p = p.Remove(x - dal, 1)
            p = p.Insert(x - dal, "+")
    
            Return x
        End Function
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            TextBox1.Text = EstraiACaso()
            TextBox2.Text = p
        End Sub
    End Class

    ciao.

    mario formosa

    mercoledì 13 febbraio 2013 18:29
  • Hello Daniele1970,
    vediamo se ho capito: dati due estremi (interi) vuoi una funzione che ad
    ogni richiamo estragga un numero casuale interno all'intervallo descritto
    dai due estremi e non uguale ad una lista di numeri precedentemente estratti.
    Giusto?
    Se si, guarda il codice del mio post e vedrai che il codice fa esattamente
    quello.
    Sbagliato?
    Allora spiegati meglio perchè mi sa che non ho capito :-(
     
     
    mercoledì 13 febbraio 2013 18:42
    Moderatore
  • Grazie Mario direi che ci siamo fa quello che volevo

    Daniele

    mercoledì 13 febbraio 2013 18:53
  • Hello Daniele1970,
    scusa se intervengo e dico la mia.
    Il codice di Mario è sicuramente funzionante, ma come sostengo da tempo (ma
    ho l'impressione che nessuno ne prenda atto), VB.NET è un linguaggio ad oggetti
    che utilizza il framework .NET.
    Questo significa che si dovrebbe (a mio personalissimo modo di vedere, ma
    poi uno è libero di fare quello che gli pare) cercare di avere un approccio
    a classi.
    Nel caso del codice di Mario (che ripeto funziona benissimo e non ci sono
    dubbi), le funzioni Randomize, Rnd, StrDup e Now sono presenti per compatibilità
    con il passato e sono caratteristiche di Visual Basic (non a caso appartengono
    all'assembly Microsoft.VisualBasic e non a quelli System.xxxx) e, sempre
    a mio modo di vedere, si dovrebbe cercare di evitarne l'utilizzo quando questo
    è possibile.
    Nella fattispecie:
    - la funzione Randomize si può sostituire con la creazione di un oggetto
    Random con l'apposito costruttore che accetta un seed (http://msdn.microsoft.com/en-us/library/ctssatww(v=vs.100).aspx)
    - per la StrDup è sufficiente creare una stringa utilizzando il costruttore
    apposito della classe String (http://msdn.microsoft.com/en-us/library/xsa4321w(v=vs.100).aspx)
    - la funzione Rnd altro non è che la chiamata del metodo Next in uno dei
    suoi tanti overload (http://msdn.microsoft.com/en-us/library/13td4hz1(v=vs.100).aspx)
    - la Now si può facilmente sostituire con DateTime.Now (http://msdn.microsoft.com/en-us/library/system.datetime.now(v=vs.100).aspx)
     
    Scusate la puntualizzazione, ma finchè utilizziamo le funzioni di retrocompatibilità
    invece che ragionare con le classi del framework comune a tutti i linguaggi,
    gli Sharpisti (quelli che usano C#) hanno tutto il diritto di ritenerci degli
    arretrati!
     
     
    mercoledì 13 febbraio 2013 20:10
    Moderatore
  • Ciao Massimo sicuramente il tuo codice fnzione alla perfezione ma come avrai letto nel mio primo post

    non sono esperto della programmazione, anzi sono piuttosto indietro rispetto alle vostre competenze, dunque  e' chiaro che sono io a non averlo capito, mi sono iscritto a questo forum per cercare di capire come funziona il codice che magari incollo pari pari alla mia applicazione, credo sia un modo per studiare , oltre naturalmente ad alcuni testi che ho acquistato, per quanto riguarda la domanda posta in origine chiedevo che da un elenco di numeri  tipo un array

    {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} il numero estratto venisse cancellato dalla matrice esempio estraggo il 10, l'estrazione successiva scegliesse un numero tra

    {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12} e cosi' via e magari ad ogni chiamata con la funzione redim l'estazione venisse fatta su 11 numeri e non 12

    ho fatto l'esempio della tobola perche' alla prima estrazione nel sacchetto ci sono 90 numeri, nella seconda il sacchetto avra 89 poi 88 fino a quando il sacchetto sara' vuoto. nei codici che ho provato mi pare di aver capito che l'estrazione si basi un concetto diverso,cioe' si estrae un numero elo si mette in una variabile nell'estrazione successiva si prenda il numero estratto e lo si confronti con quello nella variabile, poi se e' il solito numero lo si ignora e si procede a una nuova estrazione sempre pero' su una base di numeri sempre uguale (20, 50) cioe' su una base di 30numeri

    nell'esempio di prima {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} potrebbero pero' essere anche non sequenziali {4, 2, 12, 4, 5, 6, 7, 8, 9, 10, 11, 11} e con la probabilita che tra di essi ci siano anche dei duplicati credo di essermi spiegato un po' meglio ora

    Comunque grazie per il tempo che dedicate ai primcipianti

    Daniele


    mercoledì 13 febbraio 2013 20:51
  • Ciao Daniele1970,

    Ciao Massimo sicuramente il tuo codice fnzione alla perfezione ma come avrai letto nel mio primo post

    non sono esperto della programmazione, anzi sono piuttosto indietro rispetto alle vostre competenze, dunque  e' chiaro che sono io a non averlo capito, mi sono iscritto a questo forum per cercare di capire come funziona il codice che magari incollo pari pari alla mia applicazione, credo sia un modo per studiare , oltre naturalmente ad alcuni testi che ho acquistato, per quanto riguarda la domanda posta in origine chiedevo che da un elenco di numeri  tipo un array

    {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} il numero estratto venisse cancellato dalla matrice esempio estraggo il 10, l'estrazione successiva scegliesse un numero tra

    {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12} e cosi' via e magari ad ogni chiamata con la funzione redim l'estazione venisse fatta su 11 numeri e non 12

    ho fatto l'esempio della tobola perche' alla prima estrazione nel sacchetto ci sono 90 numeri, nella seconda il sacchetto avra 89 poi 88 fino a quando il sacchetto sara' vuoto. nei codici che ho provato mi pare di aver capito che l'estrazione si basi un concetto diverso,cioe' si estrae un numero elo si mette in una variabile nell'estrazione successiva si prenda il numero estratto e lo si confronti con quello nella variabile, poi se e' il solito numero lo si ignora e si procede a una nuova estrazione sempre pero' su una base di numeri sempre uguale (20, 50) cioe' su una base di 30numeri

    nell'esempio di prima {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} potrebbero pero' essere anche non sequenziali {4, 2, 12, 4, 5, 6, 7, 8, 9, 10, 11, 11} e con la probabilita che tra di essi ci siano anche dei duplicati credo di essermi spiegato un po' meglio ora

    Comunque grazie per il tempo che dedicate ai primcipianti

    Daniele

    infatti l'esempio che ti ho postato precedentemente e quello di Massimo fanno ciò che chiedi , se guardi il mio esempio trovi il metodo Remove()  , come spiegato questo metodo elimina il numero dalla collection in modo che alla successiva estrazione esempio estrai il numero 10 , sarà come tu hai detto da 1 a 20 senza tenere conto di tale numero.

    Se posso consigliarti dalla mia piccola esperienza da appassionato e non sviluppatore di professione ,  la cosa migliore e sempre quella di studiare per lo meno i concetti della programmazione ad oggetti ( essendo il net framework tale ) , mantenersi sempre aggiornato sul proseguo di questa tecnologia , e fare molta ma molta pratica , studiare il codice a mio avviso serve a poco , se non quello di capire il codice di quella determinata funzione  , ma poi la creazione di un progetto , piccolo o grosso che sia dipende da te , dovrai tu creare il codice secondo quello che l'applicazione deve fare e i piccoli o grandi contributi che trovi in qua e la per la rete ti sono semplicemente di aiuto.

    Ciao. 



    mercoledì 13 febbraio 2013 21:01
  • Grazie Massimo per il tuo contributo che in effetti puntualizza una cosa molto importante e mi scuso se anche io sono tra quelli che non prendono atto nella giusta maniera che Vb.net è un linguaggio Orientato agli Oggetti.

    Per quanto mi riguarda, eviterò in futuro di usare ciò che è obsoleto, e dalla library ho notato che ci sono anche elementi delle versioni del framework precedenti alla 4.5 che sono dichiarati obsoleti.

    Quindi devono stare in allerta anche gli Sharpisti :) :) :) :) :) !

    Tuttavia secondo il mio modestissimo punto di vista, tutto è un po' arretrato :) !

    Infine la versione migliorata del mio codice precedente.

    Public Class Form7
        Dim dal As Integer = 59
        Dim al As Integer = 63
        Dim p As String
        Dim g As Random
        Private Sub Form7_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            g = New Random(DateTime.Now.Millisecond)
            reset()
        End Sub
        Sub reset()
            p = New String("-", al - dal + 1)
        End Sub
        Function EstraiACaso() As Integer
            Dim x As Integer
            If p = New String("+", al - dal + 1) Then
                MsgBox("Numeri finiti")
                Return -1
            End If
            x = g.Next(dal, al + 1)
            Do While p.Substring(x - dal, 1) = "+"
                x = g.Next(dal, al + 1)
            Loop
            p = p.Remove(x - dal, 1)
            p = p.Insert(x - dal, "+")
            Return x
        End Function
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            TextBox1.Text = EstraiACaso()
        End Sub
    End Class

    Ciao.

    mario formosa

    mercoledì 13 febbraio 2013 22:09
  • Hello Daniele1970,
    perdonami ma non sono daccordo sulla modalità classica di "imparare" del
    programmatore (non nel caso specifico ma in generale).
    Un informatico, alla fine, progetta applicazioni (piccole o grandi che siano),
    quindi è una sorta di geometra o architetto del software.
    Ora, a meno che non mi sbagli, l'architetto o il geometra standard (quello
    delle case) non si mette a costruire case prendendo muri dalle altre per
    imparare ma, preventivamente, studia (almeno le basi).
    E' evidente (e lo capisco benissimo) che prendere ed incollare del codice
    funzionante per poi cercare di capirlo da l'impressione di accelerare la
    comprensione dello stesso, ma se non fosse il codice giusto? Se non fosse
    la modalità corretta per risolvere il problema?
    Come fai saperlo se non hai le basi?
    Non dico di studiare lo scibile informatico, ma le basi su cui si fonda un
    framework debbono a mio personalissimo modo di vedere essere studiate.
    In ogni caso, se guardi il mio codice riportato nell'altro thread, l'estrazione
    avviene dal "sacchetto" Enumerable.Range() e, quindi, se il tuo sacchetto
    non è composto da numeri interi consecutivi (ad esempio {4, 2, 12, 4, 5,
    6, 7, 8, 9, 10, 11, 11}), ti basta sostituirlo.
     
    In pratica, potresti avere una funzione che accetta il "sacchetto" da cui
    estrarre, estrae un numero e lo rimuove dal sacchetto:
     
    Public Function EstraiNumero2(sacchetto As ICollection(Of Integer)) As Integer
       If sacchetto Is Nothing Then Throw New ArgumentNullException()
       If sacchetto.Count = 0 Then Return -1
       ' Creo l'oggetto per l'estrazione dei numeri casuali
       Dim rnd As New Random(DateTime.Now.Millisecond)
       ' Recupero il numero casuale tra quelli non estratti
       Dim number = sacchetto.Skip(rnd.Next(sacchetto.Count)).Take(1).First()
       sacchetto.Remove(number)
       Return number
    End Function

     
     

    giovedì 14 febbraio 2013 07:45
    Moderatore
  • Quello che dici e' giusto. E' vero il geometra non prende un muro da una casa per metterlo in un'altra

    e' anche vero pero' che se un geometra vede qualcosa di ben fattto cerchera' il piu' possibile di studiarlo. per quanto riguarda le basi sono pienamente daccordo con te, infatti come ho scritto nel post ho acquistato dei testi che sto leggendo quotidianamente. Mi sono "infilato" in questo forum forse troppo presto. Se conosci dei testi validi ti chiedo cortesemente di fornirmene i titoli.

    Daniele

    giovedì 14 febbraio 2013 13:27
  • Hello Daniele1970,
    sei nel posto adatto.
    Questo forum ha proprio questo scopo.
    Inoltre sei esattamente nell'ottica che dico io: il geometra studia il muro
    e lo rifà! Esattamente quello che intendo io.
    Il mio discorso vale in generale, non solo in questo thread (che si interrompe
    qui altrimenti andiamo off-topic :-) ), capita spesso di vedere codice buttato
    nel forum senza un minimo di ragionamento e spiegazione e, questo, non aiuta
    chi cerca di capire.
    Sei il benvenuto qui e siamo onorati se possiamo esserti d'aiuto.
     
     
    giovedì 14 febbraio 2013 14:42
    Moderatore