WN

WN (https://www.wn.se/forum/index.php)
-   Serversidans teknologier (https://www.wn.se/forum/forumdisplay.php?f=4)
-   -   5 siffror i slumpmässig ordning? asp.net c# (https://www.wn.se/forum/showthread.php?t=1055937)

naak2803 2012-12-01 00:38

5 siffror i slumpmässig ordning? asp.net c#
 
Hej,

Nu kanske jag är trött en fredagsnatt...
men hur kan jag i c# få 5 siffror i slumpmässig ordning?
siffror ska vara 1-5 och samma siffra ska inte upprepas.

ex
1 5 4 2 3
3 5 4 2 1
1 5 2 1 3

naak2803 2012-12-01 01:57

lyckades komma på lösningen själv...

Kod:

Random random = new Random();
        var nums = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9};
        List<int> result = new List<int>();

        int iNumberOfSlides = nums.Count;

        while (nums.Count > 0)
        {
            int idx = random.Next(0, nums.Count);
            result.Add(nums[idx]);
            nums.RemoveAt(idx);
        }

        string sHTML = string.Empty;

        for (int i = 0; i < iNumberOfSlides; i++)
            sHTML += "<a href='#'><img src='Images/Sliders/" + result[i].ToString() + ".jpg' /></a>";

kanske inte smidigaste sättet.. men men.. it works!

Conny Westh 2012-12-02 02:42

Jag skulle rekommendera att du alltid tar för vana att lägga ut programkod i egna klasser så det ligger så lite kod i ASP/Webbsidorna som möjligt, nu se jag inte exakt hur du gjort men jag bidrar här även med en förbättring av din slumpfunktion, för den behöver initieras med ett slumpmässigt värde annars kommer den att upprepa samma sekvens av tal om du startar programmet i morgon.

För att testa att slumpmässigheten är effektiv så måste man anropa samma funktion många gånger i rad och se att man inte kan uppfatta en regelbundenhetr i slumtalen.

Först lite testkod....
Kod:

// Class: Program
// Author: Conny Westh
// Date Created: 2012-12-02
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace wn.random.number
{
        class Program
        {
                static void Main(string[] args)
                {
                        List<int> numbers;

                        Console.WriteLine("Test av slumptal...");
                        Console.WriteLine();

                        // Testa slumpfunktionen många gånger för att se att
                        // den inte upprepas i regelbundna mönster....
                        for (int n = 0; n < 17; n++)
                        {
                                // Tänk på att skapa ny lista varje gång annars blir det knas...
                                numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
                                foreach (int i in RandomNumber.SortIntItemsRandomly(numbers))
                                {
                                        Console.Write(String.Format("{0} ", i));
                                }
                                Console.WriteLine();
                        }

                        Console.WriteLine();
                        Console.WriteLine("Press any key to exit...");
                        Console.ReadKey();
                }
        }
}

Sen kommer funktionen som TS är ute efter....
Kod:

// Class: RandomNumber
// Author: Conny Westh
// Date Created: 2012-12-02
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace wn.random.number
{
        public class RandomNumber
        {
                public static List<int> SortIntItemsRandomly(List<int> nums)
                {
                        Random random = new Random();
                        List<int> result = new List<int>();

                        int iNumberOfSlides = nums.Count;

                        while (nums.Count > 0)
                        {
                                // Funkar inte så bra, för random måste initieras
                                // med ett slumpmässit frö annars får man upprepade serier av slumptal
                                //int idx = random.Next(0, nums.Count);

                                // Dett afunkar bättre med den funktion jag använder,
                                // blir mer oförutsägbart resultat....
                                int idx = Slump.slumpInt(0, nums.Count);
                                result.Add(nums[idx]);
                                nums.RemoveAt(idx);
                        }
                        return result;
                }
        }
}

Sen kommer min egen Slu,p-klass som jag skapade i våras, som ser till att slumpmässigheten blir lite bättre ....
Kod:

// Class: Slump
// Author: Conny Westh
// Date Created: 2012-05-23
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace wn.random.number
{
        public static class Slump
        {
                private static int seed = Environment.TickCount;
                public static double slumptal
                {
                        get
                        {
                                Random rnd = new Random(seed++);
                                return rnd.NextDouble();
                        }
                }

                public static int slumpInt(int low, int high)
                {
                        Random rnd = new Random(seed++);
                        int range = high - low;
                        if (range <= 0)
                        {
                                return low;
                        }
                        else
                        {
                                return (rnd.Next() % range) + low;
                        }
                }

                public static long slumpLong(long low, long high)
                {
                        Random rnd = new Random(seed++);
                        long range = high - low;
                        if (range <= 0L)
                        {
                                return low;
                        }
                        else
                        {
                                return (rnd.Next() % range) + low;
                        }
                }

        }
}

Den här koden är skapad i en Console-applikation för att vara lätt att testa, men det är bara att strunta i att ta med Program-klassen så kan man använda de andra två i sina webbprojekt, eftersom de inte innehåller någon interaktion med Consolen, utan är helt "rena" klasser (dvs rena från UI-kod) och de är därför återanvändbara i många olika sammanhang.

Namespace kan ju ändras till valfritt, eftersom det inte är något som krävs i övrigt av klasserna.

yakuzaemme 2012-12-02 03:41

Kod:

class MittProgram
    {
        static Random Rand = new Random();
        static List<String> Sliders = new List<String>();
        static void Main(string[] args)
        {
            AddSliders();
            String MyHTML = SliderHTML();
        }

        static void AddSliders()
        {
            for (Int32 x = 0; x < 10; x++)
            {
                String Current = String.Empty;
                for (Int32 i = 0; i < 5; i++)
                {
                    Int32 Num = Rand.Next(1, 6);
                    while (Current.Contains(Num.ToString()))
                    {
                        Num = Rand.Next(1, 6);
                    }
                    Current += Num.ToString();
                }
                Sliders.Add(Current);
            }
        }
        static String SliderHTML()
        {
            String sHTML = String.Empty;
            foreach (String slider in Sliders)
                sHTML += "<a href='#'><img src='Images/Sliders/" + slider + ".jpg'/></a>";
            return sHTML;
        }
    }

.

Conny Westh 2012-12-02 06:45

Ska vi tjafsa om kortaste koden så vill jag ha sista ordet:

Den här koden är allt som behövs för att sortera en lista i slumpmässig ordning om man kör C#:
Kod:

static int seed = Environment.TickCount;
numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var rnd = new Random(seed++);
numbers = numbers.OrderBy(x => rnd.Next()).ToList();


Nerix 2012-12-02 15:03

Å här är samma lösning i Ruby

Kod:

(1..5).to_a.shuffle

Conny Westh 2012-12-02 21:46

Citat:

Ursprungligen postat av Nerix (Inlägg 20456718)
Å här är samma lösning i Ruby

Kod:

(1..5).to_a.shuffle

Det löser inte problemet, eftersom TS vill ha en array med valfria värden. Det är inte som i exemplet bara att räkna upp siffrorna 1-5. Dessutom måste man ha ett slumpfrö så slumpserien inte upprepas vid nästa körning.

Nerix 2012-12-02 22:29

Citat:

Ursprungligen postat av ConnyWesth (Inlägg 20456726)
Dessutom måste man ha ett slumpfrö så slumpserien inte upprepas vid nästa körning.

Så du menar att Array#shuffle returnerar samma serie om den körs två gånger efter varandra?

Det är ju inte så att implementeringen ser ut så här.

http://imgs.xkcd.com/comics/random_number.png

Så här säger dokumentationen, vilket verkar helt logiskt.

Citat:

By default, the parameterless constructor of the System.Random class
(which is what "rand" is using) uses the system time as the initial seed.
Every time you ask for a random number, we create a new Random object.

Conny Westh 2012-12-02 22:36

Jag jobbar ju inte med Ruby men i de flesta programspråk jag kört genom åren så måste man alltid själv definiera ett "frö", men som du visade så var det tydligen redan gjort i den funktion du använde.

Exempelvis skulle koden:
Kod:

numbers = new List<int>() { 23, 17, 13, 44, 51, 68, 37, 58, 9 };
var rnd = new Random();
numbers = numbers.OrderBy(x => rnd.Next()).ToList();

Ge samma resultat om man startar om programmet och kör igen. Det är det normala i de flesta pogramspråk.

I NET kan man lägga tilll följande kodelement för att själv styra fröet som styr slumpgenereringen. Static framför seed-variabeln gör att variabeln håller kvar sitt värde om den ligger som klassvariabel i en slumptalsklass, trots att man anropar slumpmetoden som en staticmetod, vilken var en liten behändig egenskap i sig.
Kod:

static int seed = Environment.TickCount;
var rnd = new Random(seed++);

Men däremot så var funktionen felaktig utifrån kravet, det gör inte vad kravställaren vill. Dvs väljer ett slumpmässigt element från en angiven lista där varje element är en int. Din lista visade bara siffrorna 1-5. utan någon initiering från användaren med valfria värden.

Listan skulle likväl kunnat innehålla följande värden:
Kod:

static int seed = Environment.TickCount;
var rnd = new Random(seed++);
numbers = new List<int>() { 23, 17, 13, 44, 51, 68, 37, 58, 9 };
numbers = numbers.OrderBy(x => rnd.Next()).ToList();

Nog om slumptal. Visa gärna hur du initierar med valfria heltalsvärden i en array i stället.

Nerix 2012-12-02 23:00

Citat:

Ursprungligen postat av ConnyWesth (Inlägg 20456730)
Jag jobbar ju inte med Ruby men i de flesta programspråk jag kört genom åren så måste man alltid själv definiera ett "frö", men som du visade så var det tydligen redan gjort i den funktion du använde.

Exempelvis skulle koden:
Kod:

numbers = new List<int>() { 23, 17, 13, 44, 51, 68, 37, 58, 9 };
var rnd = new Random();
numbers = numbers.OrderBy(x => rnd.Next()).ToList();

Ge samma resultat om man startar om programmet och kör igen. Det är det normala i de flesta pogramspråk.

I NET kan man lägga tilll följande kodelement för att själv styra fröet som styr slumpgenereringen. Static framför seed-variabeln gör att variabeln håller kvar sitt värde om den ligger som klassvariabel i en slumptalsklass, trots att man anropar slumpmetoden som en staticmetod, vilken var en liten behändig egenskap i sig.
Kod:

static int seed = Environment.TickCount;
var rnd = new Random(seed++);

Men däremot så var funktionen felaktig utifrån kravet, det gör inte vad kravställaren vill. Dvs väljer ett slumpmässigt element från en angiven lista där varje element är en int. Din lista visade bara siffrorna 1-5. utan någon initiering från användaren med valfria värden.

Listan skulle likväl kunnat innehålla följande värden:
Kod:

static int seed = Environment.TickCount;
var rnd = new Random(seed++);
numbers = new List<int>() { 23, 17, 13, 44, 51, 68, 37, 58, 9 };
numbers = numbers.OrderBy(x => rnd.Next()).ToList();

Nog om slumptal. Visa gärna hur du initierar med valfria heltalsvärden i en array i stället.

Kod:

[23, 17, 13, 44, 51, 68, 37, 58, 9].shuffle

yakuzaemme 2012-12-02 23:05

Conny, hur menar du att Random() ger samma resultat om man kör det igen? Du måste inte ge något frö för att det inte ska bli samma som förut, och du behöver heller inte specificera Environment.Tickcount, för den är redan baserad på tid.

Conny Westh 2012-12-02 23:11

Fast du får nog kolla dokumentationen en gång till i Ruby, för jag sökte på: "Ruby Random Seed" och hittade följande artikel: http://www.ruby-forum.com/topic/158679

Där en programmerare hade konstaterat vad jag befarade skulle hända. Upprepade slumptal, när Random anropas flera gånger.

Nerix 2012-12-02 23:14

Citat:

Ursprungligen postat av ConnyWesth (Inlägg 20456734)
Fast du får nog kolla dokumentationen en gång till i Ruby, för jag sökte på: "Ruby Random Seed" och hittade följande artikel: http://www.ruby-forum.com/topic/158679

Där en programmerare hade konstaterat vad jag befarade skulle hända. Upprepade slumptal, när Random anropas flera gånger.

Artikeln är 4 år gammal, alltså Ruby 1.8.x, inte 1.9.x

Conny Westh 2012-12-02 23:18

Citat:

Ursprungligen postat av yakuzaemme (Inlägg 20456733)
Conny, hur menar du att Random() ger samma resultat om man kör det igen? Du måste inte ge något frö för att det inte ska bli samma som förut, och du behöver heller inte specificera Environment.Tickcount, för den är redan baserad på tid.

Ja, så är det. random måste initieras med ett frö som man tvingar vara oregelbundet annars kommer slumpserien att riskera att upprepas vid flera anrop. Bland annat måste du som jag exepmplifierat skriva seed++ i anropet till random så att det vid extremt hög anropsfrekvens ska vara garanterat olika frö.

Detta är inget ovanligt utan så har alla programspråk fungerat sedan jag först började programmera på slutet av 1970-talet. Nu har jag även konstaterat att Ruby inte är något undantag utan man måste initiera med ett "frö" för att hindra att slumpserien upprepas, det är fortfarande ingen garanti att talet är slumpmässigt men det är det bästa man kan åstadkomma i datorn idag.

Sök på "Random seed" på internet så hittar du säkert massvis med artiklar just om detta fenomen.

yakuzaemme 2012-12-02 23:30

Citat:

Ursprungligen postat av ConnyWesth (Inlägg 20456737)
Ja, så är det. random måste initieras med ett frö som man tvingar vara oregelbundet annars kommer slumpserien att riskera att upprepas vid flera anrop. Bland annat måste du som jag exepmplifierat skriva seed++ i anropet till random så att det vid extremt hög anropsfrekvens ska vara garanterat olika frö.

Du skrev:
"Ge samma resultat om man startar om programmet och kör igen. Det är det normala i de flesta pogramspråk."

Vilket inte är sant. Skulle jag kopiera din kod och köra den två gånger i rad så finns det inte en chans i världen att det skulle bli samma resultat. Du får mer "säkerhet" genom att ange ett frö, eftersom ingenting är helt slumpmässigt (logiskt?), men TS behöver verkligen inte ange ett frö, och därför behöver du inte kommentera det, eller påstå att han måste/bör det.

Conny Westh 2012-12-02 23:33

Här är en mer aktuell artikel om Ruby: http://ruby.about.com/od/newinruby19...rs-In-Ruby.htm

Men observera att jag inte tycker Ruby är "sämre" eller dåligt på att hantera slumptal, det är datorn som hårdvara som sätter gränsen för hur slumpmässigt ett ta l kan vara, så samma förutsättningar gäller för alla programspråk som körs på samma dator.

Citat:

It can be useful in a range programs, typically games and simulations, to generate random numbers. While no computer can generate truly random numbers, Ruby does provide access to a method that will return pseudorandom numbers.

Not Exactly Random
No computer can generate truly random numbers purely by computation. The best they can do is to generate pseudorandom numbers, a sequence of numbers that appears random but is not random. To a human observer, these numbers are indeed random. There will be no short repeating sequences, and, at least to the human observer, be completely random. However, given enough time and motivation, the original seed can be discovered, the sequence recreated and the next number in the sequence guessed. For this reason, the methods discussed in this article should probably not be used to generate numbers that must be cryptographically secure.

As mentioned above, pseudorandom number generators PRNGs must be seeded in order to produce sequences that differ each time a new random number is generated. Remember that no method is magical, these seemingly random numbers are generated using relatively simple algorithms using relatively simple arithmetic. By seeding the PRNG, you're starting it off at a different point every time. If you didn't seed it, it would generate the same sequence of numbers each time. But, at least in Ruby, the developers have thought of this.

Conny Westh 2012-12-02 23:48

Citat:

Ursprungligen postat av yakuzaemme (Inlägg 20456739)
Du skrev:
"Ge samma resultat om man startar om programmet och kör igen. Det är det normala i de flesta pogramspråk."

Vilket inte är sant. Skulle jag kopiera din kod och köra den två gånger i rad så finns det inte en chans i världen att det skulle bli samma resultat. Du får mer "säkerhet" genom att ange ett frö, eftersom ingenting är helt slumpmässigt (logiskt?), men TS behöver verkligen inte ange ett frö, och därför behöver du inte kommentera det, eller påstå att han måste/bör det.

Du borde kanske läsa på lite bättre vad slumpmässighet är i datorsammanhang. Det finns hur mycket som helst skrivet om "Random seed" på internet, alla programspråk har samma problem och det beror på att hårdvaran är det som bestämmer hur "slumpmässigt" ett tal kan genereras från ett program.

Programmet använder något typ av matematisk formel för att beräkna ett tal som ska vara pseudoslumpmässigt.

Matematik är per definition väldigt förutsägbart. men även på en kvantmekansisk nivå är datorn mycket förutsägbar. Det är bara vi människor som "upplever" att talen genereras slumpmässigt för att det är en så komplex formel att vi inte kan överblicka den med våra sinnen och intellekt.

yakuzaemme 2012-12-03 00:10

Och även jag säger samma sak, och gjorde det i min tidigare post. Det jag säger dock är att TS ej behöver ange ett frö, och du får det att verka som att det är absolut nödvändigt.

"// med ett slumpmässit frö annars får man upprepade serier av slumptal"
"Dessutom måste man ha ett slumpfrö så slumpserien inte upprepas vid nästa körning."
"men i de flesta programspråk jag kört genom åren så måste man alltid själv definiera ett "frö""

Det du säger är fel, och det var det jag poängterade.

SimonP 2012-12-03 12:32

Det beror på vad man skall göra, skall man använda programmet i kommersiella syften ska man inte använda de vanliga random() funktionerna, oavsett språk. De genererar alldeles för dåliga slumptal. Många språk har bättre alternativ, Java och Ruby har SecureRandom, PHP har mt_rand() osv.

dAEk 2012-12-03 18:29

Jag tänkte inte ge mig in i debatten förutom att jag tror att Conny har fel i det här fallet. Man borde inte behöva ange seed när man skapar en ny instans av Random() eftersom den parameterlösa konstruktorn i sin tur anropar this(Environment.TickCount) vilket alltså ser ut att göra samma sak som att man själv skickar in värdet.

Vad Ruby har att göra i den här tråden där TS specifikt frågade efter C# har jag svårt att se.

SimonP 2012-12-03 19:26

Citat:

Ursprungligen postat av dAEk (Inlägg 20456792)
Jag tänkte inte ge mig in i debatten förutom att jag tror att Conny har fel i det här fallet. Man borde inte behöva ange seed när man skapar en ny instans av Random() eftersom den parameterlösa konstruktorn i sin tur anropar this(Environment.TickCount) vilket alltså ser ut att göra samma sak som att man själv skickar in värdet.

Vad Ruby har att göra i den här tråden där TS specifikt frågade efter C# har jag svårt att se.

Fast det är många språk som inte automatseedar, då blir resultatet som Conny skriver, samma slumptal vid varje ny exekvering. Det är fullt möjligt att ASP.NET inte automatseedar (har inte testat ASP.NET själv).

Dessutom varierar det beroende på platform, PHP:s rand() på Windows brukar ge extremt dåliga slumptal, medans PHP:s rand() på Linux ger hyffsade tal. Men även om man seedar själv är det som sagt inte många standard PRNG:s som klarar en DieHard test: http://en.wikipedia.org/wiki/Diehard_tests

dAEk 2012-12-03 20:11

Citat:

Ursprungligen postat av SimonP (Inlägg 20456799)
Fast det är många språk som inte automatseedar, då blir resultatet som Conny skriver, samma slumptal vid varje ny exekvering.

Jo, men hur andra språk funkar är väl inte intressant i en tråd som rör ett specifikt språk? Äh, låt oss släppa det och gå vidare :)

Conny Westh 2012-12-03 22:12

Här är lite mer artiklar om RNG-området, som ger utförligare bakgrundsförklaringar....


http://www.stat.fsu.edu/pub/diehard/

http://www.codeproject.com/Articles/...ber-Generation


Alla tider är GMT +2. Klockan är nu 14:12.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson