Listedeki rastgele öğeye nasıl erişilir?


233

Bir ArrayList var ve bir düğmeye tıklayın ve sonra rasgele bu listeden bir dize seçin ve bir ileti kutusunda görüntülemek gerekir.

Bunu nasıl yapabilirim?

Yanıtlar:


404
  1. Bir Randomyerde bir sınıf örneği oluşturun . Rastgele bir sayıya her ihtiyacınız olduğunda yeni bir örnek oluşturmamanın oldukça önemli olduğunu unutmayın. Oluşturulan sayılardaki bütünlüğü sağlamak için eski örneği yeniden kullanmalısınız. Bir staticyerde bir alanınız olabilir (iş parçacığı güvenliği sorunlarına dikkat edin):

    static Random rnd = new Random();
  2. Örnekte, Randomaşağıdakilerdeki maksimum öğe sayısıyla birlikte rastgele bir sayı vermesini isteyin ArrayList:

    int r = rnd.Next(list.Count);
  3. Dizeyi görüntüle:

    MessageBox.Show((string)list[r]);

Bir sayının tekrarlanmaması için bunu değiştirmenin iyi bir yolu var mı? Bir kerede rastgele bir kart seçerek bir deste desteyi karıştırmak istediğimi ancak aynı kartı iki kez seçemediğimizi varsayalım.
AdamMc331

7
@ McAdam331 Look up Fisher-Yates Shuffle algoritması: en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
Mehrdad Afshari

2
Tahmin edilen 0 tabanlı dizinin ötesinde bir öğe max'a erişilmesini önlemek için "rnd.Next (list.Count)" yerine "rnd.Next (list.Count-1)" olmalı mı?
Shannon

22
@ B.ClayShannon Hayır. Çağrıdaki üst sınır Next(max)özeldir.
Mehrdad Afshari

1
Liste boş olduğunda ne olacak?
tsu1980

137

Genellikle bu küçük uzantı yöntemlerini kullanıyorum:

public static class EnumerableExtension
{
    public static T PickRandom<T>(this IEnumerable<T> source)
    {
        return source.PickRandom(1).Single();
    }

    public static IEnumerable<T> PickRandom<T>(this IEnumerable<T> source, int count)
    {
        return source.Shuffle().Take(count);
    }

    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
    {
        return source.OrderBy(x => Guid.NewGuid());
    }
}

Güçlü yazılan bir liste için bu şunları yazmanıza olanak tanır:

var strings = new List<string>();
var randomString = strings.PickRandom();

Sahip olduğunuz tek şey bir ArrayList ise, yayınlayabilirsiniz:

var strings = myArrayList.Cast<string>();

bunların karmaşıklığı nedir? tembel doğası O (N) olmadığı anlamına mı geliyor?
Dave Hillier

17
Bu yanıt, rasgele bir sayı seçtiğinizde listeyi yeniden karıştırır. Özellikle büyük listeler için rastgele bir dizin değeri döndürmek çok daha verimli olacaktır. Bunu PickRandom'da kullanın - return list[rnd.Next(list.Count)];
swax

Bu orijinal listeyi karıştırmaz, aslında liste yeterince büyükse verimlilik için hala iyi olmayabilir başka bir listede yapar ..
nawfal

.OrderBy (.) Başka bir liste oluşturmaz - IEnumerable <T> türünde, orijinal listede sıralı bir şekilde yinelenen bir nesne oluşturur.
Johan Tidén

5
GUID oluşturma algoritması tahmin edilemez ancak rastgele değildir. RandomBunun yerine bir örneğini statik durumda tutmayı düşünün .
Dai

90

Yapabilirsin:

list.OrderBy(x => Guid.NewGuid()).FirstOrDefault()

Güzel. ASP.NET MVC 4.5, bir liste uisng, bunu değiştirmek zorunda kaldı: list.OrderBy (x => Guid.NewGuid ()). FirstOrDefault ();
Andy Brown

3
Çoğu durumda önemli olmayacaktır, ancak bu muhtemelen rnd.Next kullanmaktan çok daha yavaştır. OTOH, IEnumerable <T> üzerinde çalışacaktır, sadece listelerde değil.
Mart'ta çözünebilir balık

12
Bunun ne kadar rastgele olduğundan emin değilim. Kılavuzlar benzersizdir, rastgele değil.
16'da bombacı

1
Bu cevabın daha iyi ve genişletilmiş bir versiyonunun olduğunu düşünüyorum ve @ solublefish'in yorumu benzer bir soruya bu cevapta (artı benim yorumum ) güzelce özetleniyor .
Neo

23

Bir Randomörnek oluşturun :

Random rnd = new Random();

Rastgele bir dize getir:

string s = arraylist[rnd.Next(arraylist.Count)];

Yine de, bunu sık sık yaparsanız Randomnesneyi yeniden kullanmanız gerektiğini unutmayın . Sınıfta statik bir alan olarak yerleştirin, böylece yalnızca bir kez başlatılır ve sonra erişilir.


20

Veya bunun gibi basit bir uzantı sınıfı:

public static class CollectionExtension
{
    private static Random rng = new Random();

    public static T RandomElement<T>(this IList<T> list)
    {
        return list[rng.Next(list.Count)];
    }

    public static T RandomElement<T>(this T[] array)
    {
        return array[rng.Next(array.Length)];
    }
}

O zaman arayın:

myList.RandomElement();

Diziler için de çalışır.

Daha OrderBy()büyük koleksiyonlar için pahalı olabileceğinden aramaktan kaçınırım . List<T>Bu amaçla dizin veya dizine benzer dizinler kullanın .


3
.NET'teki diziler zaten uygulanır, IListböylece ikinci aşırı yükleme gereksizdir.
Dai

3

Neden olmasın:

public static T GetRandom<T>(this IEnumerable<T> list)
{
   return list.ElementAt(new Random(DateTime.Now.Millisecond).Next(list.Count()));
}

2
ArrayList ar = new ArrayList();
        ar.Add(1);
        ar.Add(5);
        ar.Add(25);
        ar.Add(37);
        ar.Add(6);
        ar.Add(11);
        ar.Add(35);
        Random r = new Random();
        int index = r.Next(0,ar.Count-1);
        MessageBox.Show(ar[index].ToString());

3
Bu kod snippet'i soruyu çözebilir, ancak bir açıklama da dahil olmak üzere , yayınınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın.
gunr2171

3
maxValueYöntemin parametresinin Nexteksi bir değil, bir listede sadece birkaç öğe olması gerektiğini söyleyebilirim, çünkü bir belgeye göre " maxValue rasgele sayının özel üst sınırıdır ".
David Ferenczy Rogožan

1

Bir süredir bu ExtensionMethod kullanıyorum:

public static IEnumerable<T> GetRandom<T>(this IEnumerable<T> list, int count)
{
    if (count <= 0)
      yield break;
    var r = new Random();
    int limit = (count * 10);
    foreach (var item in list.OrderBy(x => r.Next(0, limit)).Take(count))
      yield return item;
}

Rastgele sınıf örneği eklemeyi unuttun
bafsar

1

Bir yerine daha sonra listenin içindeki öğelerin sırası çıkarma en önemli değilse ben, farklı bir yaklaşım önermek edeceğiz (ve her öğenin yalnızca bir kez seçilmesi gerekir) ListBir kullanabilirsiniz ConcurrentBagbir iş parçacığı güvenli, sırasız koleksiyon olan nesneleri:

var bag = new ConcurrentBag<string>();
bag.Add("Foo");
bag.Add("Boo");
bag.Add("Zoo");

EventHandler:

string result;
if (bag.TryTake(out result))
{
    MessageBox.Show(result);
}

TryTakeSırasız koleksiyondan bir "rastgele" nesne ayıklamak için çalışacaktır.


0

Sadece bir tane yerine daha fazla eşyaya ihtiyacım vardı. Bu yüzden şunu yazdım:

public static TList GetSelectedRandom<TList>(this TList list, int count)
       where TList : IList, new()
{
    var r = new Random();
    var rList = new TList();
    while (count > 0 && list.Count > 0)
    {
        var n = r.Next(0, list.Count);
        var e = list[n];
        rList.Add(e);
        list.RemoveAt(n);
        count--;
    }

    return rList;
}

Bununla rastgele kaç tane istediğiniz gibi öğe elde edebilirsiniz:

var _allItems = new List<TModel>()
{
    // ...
    // ...
    // ...
}

var randomItemList = _allItems.GetSelectedRandom(10); 

0

JSON dosyasından rastgele ülke adı yazdırılıyor.
Model:

public class Country
    {
        public string Name { get; set; }
        public string Code { get; set; }
    }

Implementaton:

string filePath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\..\..\")) + @"Data\Country.json";
            string _countryJson = File.ReadAllText(filePath);
            var _country = JsonConvert.DeserializeObject<List<Country>>(_countryJson);


            int index = random.Next(_country.Count);
            Console.WriteLine(_country[index].Name);

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.