Numaralandırmadan rastgele bir değeri nasıl seçerim?


171

C # 'da rastgele bir numaralandırma verildiğinde, rastgele bir değeri nasıl seçerim?

(SO hakkında bu çok temel soruyu bulamadım. Cevabımı bir dakika içinde herkes için referans olarak göndereceğim, ancak lütfen kendi cevabınızı göndermekten çekinmeyin.)

Yanıtlar:


282
Array values = Enum.GetValues(typeof(Bar));
Random random = new Random();
Bar randomBar = (Bar)values.GetValue(random.Next(values.Length));

40
randomYine de sıkı bir döngü içinde yeniden yaratmadığınızdan emin olun - aksi takdirde aynı değeri elde edersiniz.
ChrisF

1
Bu rastgele olmalı. Sonraki (değerler. Uzunluk -1)?
uriDium

7
@uriDium Hayır, değer argüman belirtir iade edilemeyecek kadar büyük olması ilk (yani maksimum eksi 1 )
mafu

Uzunluk - 1
Bojidar Stanchev

DarinDimitrov IMO tarafından @ChrisF tarafından yapılan ilk yorum, Chris'e verilen cevabın içinde bir not olmalıdır.
maytham-ɯɐɥʇʎɐɯ

62

Tüm değerlerin bir dizisini almak için Enum.GetValues ​​kullanın. Ardından rastgele bir dizi öğesi seçin.

static Random _R = new Random ();
static T RandomEnumValue<T> ()
{
    var v = Enum.GetValues (typeof (T));
    return (T) v.GetValue (_R.Next(v.Length));
}

Ölçek:

for (int i = 0; i < 10; i++) {
    var value = RandomEnumValue<System.DayOfWeek> ();
    Console.WriteLine (value.ToString ());
}

->

Tuesday
Saturday
Wednesday
Monday
Friday
Saturday
Saturday
Saturday
Friday
Wednesday

5

Bunu sadece yapabilirsiniz:

var rnd = new Random();
return (MyEnum) rnd.Next(Enum.GetNames(typeof(MyEnum)).Length);

Dizileri depolamaya gerek yok


GetNamesbir dizi döndürür.
Nathan Tuggy

Bunu saklamanız gerekmiyordu. Benim kötü
Breno Angelotti

Birisi bunu bir döngüde yapıyorsa, bir dizide önbelleğe almak yerine her seferinde GetNames'i çağırır. Bu onların kodunu yavaşlatır, bu yüzden burada katkınız ne olduğunu görmüyorum?
Bojidar Stanchev

@BojidarStanchev IF , benim durumumda bu harika çalışıyor, teşekkür ederim Breno :)
Jaacko Torus

4

İşte bir şekilde alternatif bir versiyonu Extension Methodkullanılarak LINQ.

using System;
using System.Linq;

public static class EnumExtensions
{
    public static Enum GetRandomEnumValue(this Type t)
    {
        return Enum.GetValues(t)          // get values from Type provided
            .OfType<Enum>()               // casts to Enum
            .OrderBy(e => Guid.NewGuid()) // mess with order of results
            .FirstOrDefault();            // take first item in result
    }
}

public static class Program
{
    public enum SomeEnum
    {
        One = 1,
        Two = 2,
        Three = 3,
        Four = 4
    }

    public static void Main()
    {
        for(int i=0; i < 10; i++)
        {
            Console.WriteLine(typeof(SomeEnum).GetRandomEnumValue());
        }
    }           
}

İki
Bir
Dört
Dört
Dört
Üç
İki
Dört
Bir
Üç


2

Ara Enum.GetValues; bu, numaralandırmanız için olası tüm değerleri temsil eden bir dizi döndürür. Bu diziden rastgele bir öğe seçin. Bu öğeyi orijinal numaralandırma türüne geri döndürün.


2

İşte bunun için genel bir işlev. RNG oluşturma işlemini yüksek frekans kodunun dışında tutun.

public static Random RNG = new Random();

public static T RandomEnum<T>()
{  
    Type type = typeof(T);
    Array values = Enum.GetValues(type);
    lock(RNG)
    {
        object value= values.GetValue(RNG.Next(values.Length));
        return (T)Convert.ChangeType(value, type);
    }
}

Kullanım örneği:

System.Windows.Forms.Keys randomKey = RandomEnum<System.Windows.Forms.Keys>();

Threadsafe olmayan statik bir yönteme sahip olmak oldukça tehlikelidir.
CodesInChaos

@CodesInChaos Haklısın. Random.Next () iş parçacığı için güvenli değildir ve kırıldığında sıfır döndürmeye başlar. Cevabımı bu bilgiye dayanarak güncelledim.
Whool

1

Şahsen ben uzatma yöntemlerinin bir hayranıyım, bu yüzden böyle bir şey kullanırdım (gerçekten bir uzantı olmasa da, benzer görünüyor):

public enum Options {
    Zero,
    One,
    Two,
    Three,
    Four,
    Five
}

public static class RandomEnum {
    private static Random _Random = new Random(Environment.TickCount);

    public static T Of<T>() {
        if (!typeof(T).IsEnum)
            throw new InvalidOperationException("Must use Enum type");

        Array enumValues = Enum.GetValues(typeof(T));
        return (T)enumValues.GetValue(_Random.Next(enumValues.Length));
    }
}

[TestClass]
public class RandomTests {
    [TestMethod]
    public void TestMethod1() {
        Options option;
        for (int i = 0; i < 10; ++i) {
            option = RandomEnum.Of<Options>();
            Console.WriteLine(option);
        }
    }

}

1
C # 7.3'ten itibaren genel türünüzü bir numaralandırma olarak public static T Of<T>() where T : Enum sınırlayabilirsiniz
nitzel

0

Rastgele sınıf uzantısı olarak uyarlandı:

public static class RandomExtensions
{   
    public static T NextEnum<T>(this Random random)
    {
        var values = Enum.GetValues(typeof(T));
        return (T)values.GetValue(random.Next(values.Length));
    }
}

Kullanım örneği:

var random = new Random();
var myEnumRandom = random.NextEnum<MyEnum>();

0

Ayrıca rastgele bir değer de verebilirsiniz:

using System;

enum Test {
  Value1,
  Value2,
  Value3
}

class Program {
  public static void Main (string[] args) {
    var max = Enum.GetValues(typeof(Test)).Length;
    var value = (Test)new Random().Next(0, max - 1);
    Console.WriteLine(value);
  }
}

Ama bu kütüphanemdeki gibi daha iyi bir randomizer kullanmalısın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.