Listeyi Rasgele Seç <T>


852

C # 'daki genel listenin sırasını rastgele seçmenin en iyi yolu nedir? Bir piyango tipi uygulama için onları çizmek için, rastgele bir sipariş atamak istiyorum bir listede 75 sayı sonlu bir set var.


3
Bu işlevselliği .NET'e entegre etmek için açık bir sorun var: github.com/dotnet/corefx/issues/461
Natan

5
Aşağıda belirtilen Fisher-Yates algoritmasını kullanarak IList <T> ve IEnumerable <T>
öğelerini

3
@Natan bu konuyu kapattı çünkü biri "birçok projede çalıştı ve çok sayıda kütüphane geliştirdi ve böylesi bir yönteme hiç ihtiyaç duymadı." Şimdi kendimizi araştırmamız, en iyi uygulamaları aramamız, tekerleği yeniden icat etmek için zaman kaybetmemiz gerekiyor.
Vitalii Isaenko

1
Bunu doğru mu görüyorum? 10 yıl sonra geçerli tek bir fonksiyonel cevap değil mi? Belki 75 numaralı $ list2 (75!) = 364 $ ve bunun nasıl elde edilebileceği ile bir listeyi karıştırmak için gereken entropi miktarını ele alan bir çözüm için başka bir lütufa ihtiyacımız var. Bir balıkçı-karması sırasında en az bir kez 256 bit entropi ile kriptografik olarak güvenli bir RNG bile yeniden oluşturulmalıdır.
Falco

1
Ve her zamanki kodlayıcı bu sorunu çözemezse, hepimiz sonsuza kadar olası solitaire oyunlarının% 0.01'ini hep oynadık mı?
Falco

Yanıtlar:


1135

Herhangi karıştır (I)Listdayalı bir uzantısı yöntemi ile Fisher-Yates shuffle :

private static Random rng = new Random();  

public static void Shuffle<T>(this IList<T> list)  
{  
    int n = list.Count;  
    while (n > 1) {  
        n--;  
        int k = rng.Next(n + 1);  
        T value = list[k];  
        list[k] = list[n];  
        list[n] = value;  
    }  
}

Kullanımı:

List<Product> products = GetProducts();
products.Shuffle();

Yukarıdaki kod takas adaylarını seçmek için çok eleştirilen System.Random yöntemini kullanır. Hızlı ama olması gerektiği kadar rastgele değil. Karıştırmalarınızda daha iyi bir rasgelelik kalitesine ihtiyacınız varsa System.Security'de rasgele sayı üretecini kullanın.

using System.Security.Cryptography;
...
public static void Shuffle<T>(this IList<T> list)
{
    RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider();
    int n = list.Count;
    while (n > 1)
    {
        byte[] box = new byte[1];
        do provider.GetBytes(box);
        while (!(box[0] < n * (Byte.MaxValue / n)));
        int k = (box[0] % n);
        n--;
        T value = list[k];
        list[k] = list[n];
        list[n] = value;
    }
}

Bu blogda basit bir karşılaştırma var (WayBack Machine).

Edit: Bu cevabı birkaç yıl önce yazdığından beri, birçok kişi benim karşılaştırmamdaki büyük aptal kusura işaret etmek için yorum yaptı veya bana yazdı. Tabii ki haklılar. System.Random'da amaçlandığı gibi kullanılırsa yanlış bir şey yoktur. Yukarıdaki ilk örneğimde, shngle yönteminin içindeki rng değişkenini somutlaştırıyorum; bu yöntem, yöntemin tekrar tekrar çağrılıp çağrılmayacağını soruyor. Aşağıda, bugün SO tarafından @weston'dan alınan gerçekten yararlı bir yoruma dayanan sabit, tam bir örnek bulunmaktadır.

program.cs:

using System;
using System.Collections.Generic;
using System.Threading;

namespace SimpleLottery
{
  class Program
  {
    private static void Main(string[] args)
    {
      var numbers = new List<int>(Enumerable.Range(1, 75));
      numbers.Shuffle();
      Console.WriteLine("The winning numbers are: {0}", string.Join(",  ", numbers.GetRange(0, 5)));
    }
  }

  public static class ThreadSafeRandom
  {
      [ThreadStatic] private static Random Local;

      public static Random ThisThreadsRandom
      {
          get { return Local ?? (Local = new Random(unchecked(Environment.TickCount * 31 + Thread.CurrentThread.ManagedThreadId))); }
      }
  }

  static class MyExtensions
  {
    public static void Shuffle<T>(this IList<T> list)
    {
      int n = list.Count;
      while (n > 1)
      {
        n--;
        int k = ThreadSafeRandom.ThisThreadsRandom.Next(n + 1);
        T value = list[k];
        list[k] = list[n];
        list[n] = value;
      }
    }
  }
}

31
List.Count> Byte.MaxValue ise ne olur? N = 1000 ise, 255/1000 = 0 ise, bu nedenle do döngüsü sonsuz bir döngü olacaktır, çünkü kutu [0] <0 her zaman yanlıştır.
AndrewS

18
Şunu belirtmek isterim ki, karşılaştırmanın hatalı olduğu. <Code> Yeni Rasgele () </ code> bir döngü sorunu değil, <code> Rasgele </ code> rastlantısallığı olduğu içinde açıklanması
Sven

9
Shuffle'ı hızlı bir şekilde arka arkaya birçok kez çağırıyormuş gibi (örneğin, çok sayıda kısa listeyi karıştırmak gibi) karıştırmak yerine Rasgele yöntemine bir Rastgele örneğini iletmek iyi bir fikirdir. (örn. ilk öğe daima 3. konuma taşınır).
Mark Heath

7
Sadece Random rng = new Random();bir statickarşılaştırma yapmak karşılaştırma sonrası sorunu çözmek. Her bir sonraki çağrı önceki çağrılardan sonra olacağı gibi son rastgele sonuç.
weston

5
# 2, Kripto üretecine sahip sürümün çalıştığı açık değil çünkü maksimum bayt aralığı 255 olduğundan, bundan daha büyük herhangi bir liste doğru bir şekilde karıştırılmayacak.
Mark Sowul

336

Sadece öğeleri tamamen rastgele bir sırayla karıştırmamız gerekiyorsa (sadece bir listedeki öğeleri karıştırmak için), öğeleri guid ile sipariş eden bu basit ama etkili kodu tercih ederim ...

var shuffledcards = cards.OrderBy(a => Guid.NewGuid()).ToList();

40
GUID'lerin rastgele değil benzersiz olması gerekir. Bir kısmı makine tabanlıdır, diğer bir kısmı zaman tabanlıdır ve sadece küçük bir kısmı rastgeledir. blogs.msdn.com/b/oldnewthing/archive/2008/06/27/8659071.aspx
Despertar

99
Bu güzel ve zarif bir çözüm. Bir kılavuzdan başka bir şeyin rasgelelik üretmesini istiyorsanız, başka bir şeyle sipariş verin. Örn: var shuffledcards = cards.OrderBy(a => rng.Next()); compilr.com/grenade/sandbox/Program.cs
el bombası

20
Lütfen hayır. Bu yanlış. "rastgele sipariş" tamamen bir karışıklık DEĞİL: bir önyargı tanıtmak ve daha da kötüsü, sonsuz döngülere
girme

78
@VitoDeTullio: Yanlış hatırlıyorsun. Rastgele bir karşılaştırma işlevi sağladığınızda sonsuz döngüler riskiyle karşı karşıya kalırsınız ; tutarlı bir toplam sipariş oluşturmak için bir karşılaştırma işlevi gereklidir . Rastgele bir anahtar iyidir. Bu öneri yanlıştır, çünkü kılavuzların rastgele olduğu garanti edilmez, rastgele bir anahtarla sıralama tekniği yanlış olduğu için değil .
Eric Lippert

24
@ Doug: NewGuidsadece size benzersiz bir GUID vereceğini garanti eder. Rasgelelik konusunda hiçbir garanti vermez. Benzersiz bir değer oluşturmaktan başka bir amaç için bir GUID kullanıyorsanız , bunu yanlış yapıyorsunuz demektir.
Eric Lippert

120

Burada bu basit algoritmanın tüm hantal versiyonları beni biraz şaşırttı. Fisher-Yates (veya Knuth shuffle) biraz zor ama çok kompakt. Neden zor? Çünkü rastgele sayı üretecinizin kapsayıcı veya münhasır r(a,b)olduğu yerde değer döndürüp döndürmediğine dikkat etmeniz gerekir b. Ayrıca Wikipedia açıklamasını da düzenledim, böylece insanlar orada sahte kodları körü körüne takip etmiyor ve hataları tespit etmek zor oluyor. .Net için, daha fazla uzatmadan Random.Next(a,b)hariç sayıyı döndürür b, C # / 'da nasıl uygulanabilir?

public static void Shuffle<T>(this IList<T> list, Random rnd)
{
    for(var i=list.Count; i > 0; i--)
        list.Swap(0, rnd.Next(0, i));
}

public static void Swap<T>(this IList<T> list, int i, int j)
{
    var temp = list[i];
    list[i] = list[j];
    list[j] = temp;
}

Bu kodu deneyin .


Herhangi bir kartın değiştirilebilmesi için rnd (i, list.Count) 'u rnd (0, list.Count) olarak değiştirmek daha iyi olmaz mıydı?
Donuts

16
@ Donuts - hayır. Bunu yaparsanız, karışıklık içinde önyargı ekleyeceksiniz.
Shital Shah

2
Swap <T> 'i ayrı bir yönteme ayırarak, temp için birçok gereksiz T tahsisine neden olduğunuz görülüyor.
Kil

2
LINQ'nun karıştırma performansını potansiyel olarak yavaşlatabileceğini ve özellikle kodun göreceli basitliği göz önüne alındığında, bunu kullanmamanın bir nedeni olacağını iddia ediyorum.
winglerw28

7
Ne zaman i = list.Count - 1, yani son yineleme rnd.Next(i, list.Count)size geri vereceğim. Bu nedenle i < list.Count -1döngü koşulu olarak ihtiyacınız vardır . Peki, buna ihtiyacınız yok, ama 1 iterasyon tasarrufu sağlıyor;)
Pod

78

IEnumerable için genişletme yöntemi:

public static IEnumerable<T> Randomize<T>(this IEnumerable<T> source)
{
    Random rnd = new Random();
    return source.OrderBy<T, int>((item) => rnd.Next());
}

3
İş parçacığı için güvenli bir listede kullanılsa bile, iş parçacığı açısından güvenli olmadığını unutmayın
BlueRaja - Danny Pflughoeft 25:05

1
bu işleve <string> listesini nasıl veririz?
MonsterMMORPG

8
Bu algoritma ile ilgili iki önemli sorun vardır: - OrderByöğeleri (görünüşte rastgele) tuşlarına göre sıralamak için bir QuickSort varyantı kullanır. QuickSort performansı O (N log N) ; aksine, bir Fisher-Yates karıştırması O (N) 'dir . 75 öğeden oluşan bir koleksiyon için bu çok önemli olmayabilir, ancak fark daha büyük koleksiyonlar için telaffuz edilecektir.
John Beyer

10
... - Random.Next()bir değerler makul sözde rasgele dağılım üretebilir, ancak yok değil değerlerin benzersiz olacağını garanti. Yinelenen şifreler olasılığı ile (doğrusal olmayan) büyür N zaman kesin ulaşana kadar K 2 ^ 32 ± 1 ulaşır. OrderByQuickSort a, kararlı bir sıralama; bu nedenle, birden fazla elemanın aynı sahte rastgele indeks değeri atanması durumunda, çıkış dizisindeki sıraları giriş dizisindeki ile aynı olacaktır ; böylece "karıştırma" ya bir sapma eklenir.
John Beyer

27
@JohnBeyer: Bu önyargı kaynağından çok, çok daha büyük sorunlar var. Rastgele için sadece dört milyar olası tohum vardır, bu da orta büyüklükte bir setin olası karışıklıklarının sayısından çok daha azdır. Olası karışıkların sadece küçük bir kısmı üretilebilir. Bu önyargı, kazara çarpışmalar nedeniyle önyargıyı gölgede bırakır.
Eric Lippert

15

Fikir, öğe ve rastgele düzen ile anonim bir nesne almak ve daha sonra bu sipariş ve dönüş değerine göre öğeleri yeniden düzenlemek:

var result = items.Select(x => new { value = x, order = rnd.Next() })
            .OrderBy(x => x.order).Select(x => x.value).ToList()

3
en iyi bir liner çözümü
vipin8169 8:19

1
Sonunda bir noktalı virgül eksik
fyi

Eğer rnd hakkında emin değilseniz bunu yukarıdaki koddan önce ekleyin Random rnd = new Random ();
Greg Trevellick

10
    public static List<T> Randomize<T>(List<T> list)
    {
        List<T> randomizedList = new List<T>();
        Random rnd = new Random();
        while (list.Count > 0)
        {
            int index = rnd.Next(0, list.Count); //pick a random item from the master list
            randomizedList.Add(list[index]); //place it at the end of the randomized list
            list.RemoveAt(index);
        }
        return randomizedList;
    }


4
var listCopy = list.ToList()Gelen listesindeki tüm öğeleri patlatmaktan kaçınmak istemiyor musunuz? Bu listeleri neden boşaltmak istediğinizi gerçekten anlamıyorum.
Chris Marisic

9

DÜZENLEMERemoveAt benim önceki sürümde bir zayıflıktır. Bu çözüm bunun üstesinden gelir.

public static IEnumerable<T> Shuffle<T>(
        this IEnumerable<T> source,
        Random generator = null)
{
    if (generator == null)
    {
        generator = new Random();
    }

    var elements = source.ToArray();
    for (var i = elements.Length - 1; i >= 0; i--)
    {
        var swapIndex = generator.Next(i + 1);
        yield return elements[swapIndex];
        elements[swapIndex] = elements[i];
    }
}

İsteğe bağlı olarak Random generator, temel çerçeve uygulaması Randomiş parçacığı açısından güvenli veya gereksinimleriniz için kriptografik olarak yeterince güçlü değilse, uygulamanızı işleme enjekte edebilirsiniz.

İş parçacığı açısından güvenli kriptografik olarak güçlü bir uygulama için uygun bir uygulama Randombu cevapta bulunabilir.


İşte bir fikir, IList'i (umarım) verimli bir şekilde genişletmek.

public static IEnumerable<T> Shuffle<T>(this IList<T> list)
{
    var choices = Enumerable.Range(0, list.Count).ToList();
    var rng = new Random();
    for(int n = choices.Count; n > 1; n--)
    {
        int k = rng.Next(n);
        yield return list[choices[k]];
        choices.RemoveAt(k);
    }

    yield return list[choices[0]];
}


Bkz. Stackoverflow.com/questions/4412405/… . zaten farkında olmalısın.
nawfal

@nawfal benim geliştirilmiş uygulama görmek.
Jodrell

1
hmm yeterince adil. Öyle mi GetNextyoksa Next?
nawfal

4

Bu basit uzantı yöntemini kullanarak bunu başarabilirsiniz

public static class IEnumerableExtensions
{

    public static IEnumerable<t> Randomize<t>(this IEnumerable<t> target)
    {
        Random r = new Random();

        return target.OrderBy(x=>(r.Next()));
    }        
}

ve aşağıdakileri yaparak kullanabilirsiniz

// use this on any collection that implements IEnumerable!
// List, Array, HashSet, Collection, etc

List<string> myList = new List<string> { "hello", "random", "world", "foo", "bar", "bat", "baz" };

foreach (string s in myList.Randomize())
{
    Console.WriteLine(s);
}

3
RandomSınıf örneğini bir staticdeğişken olarak fonksiyonun dışında tutacağım . Aksi takdirde, hızlı bir şekilde arka arkaya çağrılırsa zamanlayıcıdan aynı randomizasyon tohumunu alabilirsiniz.
Lemonseed

İlginç bir not - Random sınıfını bir döngü içinde hızlı bir şekilde başlatırsanız, 0 ms ile 200 ms arasında birbirini söyleyin, o zaman aynı randomizasyon tohumunu alma şansınız çok yüksektir - bu da sonuçların tekrarlanmasıyla sonuçlanır. Bununla birlikte, Random rand = new Random (Guid.NewGuid (). GetHashCode ()); Bu, randomizasyonun Guid.NewGuid ()
Baaleos'tan

4

Bu, orijinali değiştirmemek istendiğinde tercih ettiğim bir karıştırma yöntemidir. Numaralandırılabilir bir dizi üzerinde çalışan Fisher – Yates "içten dışa" algoritmasının bir varyantıdır (uzunluğunun sourcebaşlangıçtan itibaren bilinmesi gerekmez).

public static IList<T> NextList<T>(this Random r, IEnumerable<T> source)
{
  var list = new List<T>();
  foreach (var item in source)
  {
    var i = r.Next(list.Count + 1);
    if (i == list.Count)
    {
      list.Add(item);
    }
    else
    {
      var temp = list[i];
      list[i] = item;
      list.Add(temp);
    }
  }
  return list;
}

Bu algoritma, - arasında bir aralık tahsis edilerek de uygulanabilir 0.length - 1 ve rasgele tüm endeksler tam bir kez seçilmiştir kadar geçen endeks ile rastgele seçilmiş endeksi değiştirerek endeks yorucu. Yukarıdaki kod, aynı şeyi yerine getirir, ancak ek ayırma olmadan. Ki bu oldukça düzgün.

RandomSınıf ile ilgili olarak genel amaçlı bir sayı üreteci (ve bir piyango çalıştırıyor olsaydım farklı bir şey kullanmayı düşünürdüm). Ayrıca varsayılan olarak zamana dayalı bir tohum değerine dayanır. Sorunun küçük bir hafifletilmesi, Randomsınıfın tohumlanmasıdır RNGCryptoServiceProviderveya RNGCryptoServiceProvidertekdüze seçilmiş rastgele çift kayan nokta değerleri oluşturmak için buna benzer bir yöntemde kullanabilirsiniz (aşağıya bakın), ancak piyangoyu çalıştırmak rastgele ve doğanın anlaşılmasını gerektirir. rastgelelik kaynağı.

var bytes = new byte[8];
_secureRng.GetBytes(bytes);
var v = BitConverter.ToUInt64(bytes, 0);
return (double)v / ((double)ulong.MaxValue + 1);

Rastgele bir çift oluşturma noktası (sadece 0 ile 1 arasında) bir tamsayı çözeltisine ölçeklendirmek için kullanılır. Her xzaman olacağı rastgele bir çifte dayalı bir listeden bir şey seçmeniz gerekiyorsa 0 <= x && x < 1, düz ileri.

return list[(int)(x * list.Count)];

Zevk almak!


4

Eğer ikisini kullanmak sakıncası yoksa Lists, bu muhtemelen bunu yapmanın en kolay yoludur, ancak muhtemelen en verimli veya tahmin edilemez olanı değildir:

List<int> xList = new List<int>() { 1, 2, 3, 4, 5 };
List<int> deck = new List<int>();

foreach (int xInt in xList)
    deck.Insert(random.Next(0, deck.Count + 1), xInt);

3

Sabit bir sayınız varsa (75), 75 öğeden oluşan bir dizi oluşturabilir, ardından listenizi numaralandırarak öğeleri dizideki rastgele konumlara taşıyabilirsiniz. Fisher-Yates shuffle'ı kullanarak liste numarasının dizi dizinine eşlenmesini oluşturabilirsiniz .


3

Genellikle kullanıyorum:

var list = new List<T> ();
fillList (list);
var randomizedList = new List<T> ();
var rnd = new Random ();
while (list.Count != 0)
{
    var index = rnd.Next (0, list.Count);
    randomizedList.Add (list [index]);
    list.RemoveAt (index);
}

list.RemoveAt bir O (n) işlemi olup, bu uygulamayı engelleyici derecede yavaş yapar.
George Polevoy

1
    List<T> OriginalList = new List<T>();
    List<T> TempList = new List<T>();
    Random random = new Random();
    int length = OriginalList.Count;
    int TempIndex = 0;

    while (length > 0) {
        TempIndex = random.Next(0, length);  // get random value between 0 and original length
        TempList.Add(OriginalList[TempIndex]); // add to temp list
        OriginalList.RemoveAt(TempIndex); // remove from original list
        length = OriginalList.Count;  // get new list <T> length.
    }

    OriginalList = new List<T>();
    OriginalList = TempList; // copy all items from temp list to original list.

0

İşte karıştırılmış değerlerin bir bayt dizisini döndüren verimli bir Shuffler. Asla gereğinden fazla karıştırmaz. Daha önce kaldığı yerden yeniden başlatılabilir. Gerçek uygulamam (gösterilmiyor), kullanıcının belirlediği bir yedek karıştırıcıya izin veren bir MEF bileşenidir.

    public byte[] Shuffle(byte[] array, int start, int count)
    {
        int n = array.Length - start;
        byte[] shuffled = new byte[count];
        for(int i = 0; i < count; i++, start++)
        {
            int k = UniformRandomGenerator.Next(n--) + start;
            shuffled[i] = array[k];
            array[k] = array[start];
            array[start] = shuffled[i];
        }
        return shuffled;
    }

'


0

İşte bunu yapmanın güvenli bir yolu:

public static class EnumerableExtension
{
    private static Random globalRng = new Random();

    [ThreadStatic]
    private static Random _rng;

    private static Random rng 
    {
        get
        {
            if (_rng == null)
            {
                int seed;
                lock (globalRng)
                {
                    seed = globalRng.Next();
                }
                _rng = new Random(seed);
             }
             return _rng;
         }
    }

    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> items)
    {
        return items.OrderBy (i => rng.Next());
    }
}

0
 public Deck(IEnumerable<Card> initialCards) 
    {
    cards = new List<Card>(initialCards);
    public void Shuffle() 
     }
    {
        List<Card> NewCards = new List<Card>();
        while (cards.Count > 0) 
        {
            int CardToMove = random.Next(cards.Count);
            NewCards.Add(cards[CardToMove]);
            cards.RemoveAt(CardToMove);
        }
        cards = NewCards;
    }

public IEnumerable<string> GetCardNames() 

{
    string[] CardNames = new string[cards.Count];
    for (int i = 0; i < cards.Count; i++)
    CardNames[i] = cards[i].Name;
    return CardNames;
}

Deck deck1;
Deck deck2;
Random random = new Random();

public Form1() 
{

InitializeComponent();
ResetDeck(1);
ResetDeck(2);
RedrawDeck(1);
 RedrawDeck(2);

}



 private void ResetDeck(int deckNumber) 
    {
    if (deckNumber == 1) 
{
      int numberOfCards = random.Next(1, 11);
      deck1 = new Deck(new Card[] { });
      for (int i = 0; i < numberOfCards; i++)
           deck1.Add(new Card((Suits)random.Next(4),(Values)random.Next(1, 14)));
       deck1.Sort();
}


   else
    deck2 = new Deck();
 }

private void reset1_Click(object sender, EventArgs e) {
ResetDeck(1);
RedrawDeck(1);

}

private void shuffle1_Click(object sender, EventArgs e) 
{
    deck1.Shuffle();
    RedrawDeck(1);

}

private void moveToDeck1_Click(object sender, EventArgs e) 
{

    if (listBox2.SelectedIndex >= 0)
    if (deck2.Count > 0) {
    deck1.Add(deck2.Deal(listBox2.SelectedIndex));

}

    RedrawDeck(1);
    RedrawDeck(2);

}

2
Stack Overflow'a hoş geldiniz! Lütfen büyük bir kod bloğundan ziyade cevabınıza bir açıklama eklemeyi düşünün. Buradaki amacımız, yanıtı anlamaları ve başka durumlarda uygulayabilmeleri için insanları eğitmektir. Kodunuzu yorumlar ve bir açıklama eklerseniz, yanıtınızı yalnızca bu kez soruyu soran kişiye değil, aynı sorunu yaşayan gelecekte de daha yararlı hale getireceksiniz.
starsplusplus

4
Bu kodun çoğu soru ile tamamen alakasızdır ve tek yararlı kısım temel olarak Adam Tegen'in cevabını neredeyse 6 yıl önce tekrarlamaktadır.
TC

0

Yerinde çalışmak yerine yeni bir liste döndüren ve diğer birçok Linq yönteminin yaptığı gibi daha genel olan kabul edilen cevabın basit bir şekilde değiştirilmesi IEnumerable<T>.

private static Random rng = new Random();

/// <summary>
/// Returns a new list where the elements are randomly shuffled.
/// Based on the Fisher-Yates shuffle, which has O(n) complexity.
/// </summary>
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> list) {
    var source = list.ToList();
    int n = source.Count;
    var shuffled = new List<T>(n);
    shuffled.AddRange(source);
    while (n > 1) {
        n--;
        int k = rng.Next(n + 1);
        T value = shuffled[k];
        shuffled[k] = shuffled[n];
        shuffled[n] = value;
    }
    return shuffled;
}


-5

Eski yazı kesin, ama ben sadece bir GUID kullanın.

Items = Items.OrderBy(o => Guid.NewGuid().ToString()).ToList();

Bir GUID her zaman benzersizdir ve sonuç her seferinde değiştiğinde yeniden oluşturulur.


Kompakt, ancak ardışık yeniGuid'lerin yüksek kaliteli rastgele olması için sıralanmasına referansınız var mı? Quid / uuid'in bazı sürümlerinde zaman damgaları ve diğer rasgele olmayan parçalar bulunur.
Johan Lundberg

8
Bu cevap zaten verilmiştir ve daha da kötüsü rastgele değil benzersizlik için tasarlanmıştır.
Alex Angas

-7

Bu tür bir soruna çok basit bir yaklaşım, listede bir dizi rastgele eleman takası kullanmaktır.

Sözde kodda bu şöyle görünecektir:

do 
    r1 = randomPositionInList()
    r2 = randomPositionInList()
    swap elements at index r1 and index r2 
for a certain number of times

1
Bu yaklaşımla ilgili bir sorun, ne zaman duracağını bilmek. Ayrıca yalancı rasgele sayı üretecindeki herhangi bir önyargıyı abartma eğilimi vardır.
Mark Bessey

3
Evet. Son derece verimsiz. Aynı şekilde daha iyi, daha hızlı yaklaşımlar olduğunda böyle bir yaklaşım kullanmak için hiçbir neden yoktur.
PeterAllenWebb

1
çok verimli ya da etkili değil ... N kez çalıştırmak muhtemelen birçok öğeyi orijinal pozisyonlarında bırakacaktır.
NSjonas
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.