सूची <T> रेंडम करें


852

सी # में एक सामान्य सूची के क्रम को यादृच्छिक करने का सबसे अच्छा तरीका क्या है? मुझे एक सूची में 75 संख्याओं का एक सीमित सेट मिला है, जिसमें मैं एक क्रमबद्ध क्रम आवंटित करना चाहता हूं, ताकि उन्हें एक लॉट प्रकार के आवेदन के लिए आकर्षित किया जा सके।


3
इस कार्यक्षमता को .NET में एकीकृत करने के लिए एक खुला मुद्दा है: github.com/dotnet/corefx/issues/461
Natan

5
आप इस NuGet पैकेज में दिलचस्पी ले सकते हैं , जिसमें IList <T> और IEnumerable <T> फेरबदल के लिए विस्तार विधियाँ शामिल हैं, जिनका उल्लेख नीचे दिए गए फिशर-येट्स एल्गोरिथ्म का उपयोग करके किया गया है
ChaseMedallion

3
@ नातान उन्होंने इस मुद्दे को बंद कर दिया क्योंकि किसी ने "कई परियोजनाओं पर काम किया और कई पुस्तकालयों को विकसित किया और कभी भी ऐसी विधि की आवश्यकता नहीं थी" जिसने मुझे नाराज कर दिया। अब हमें खुद को जांचना है, सबसे अच्छा कार्यान्वयन की खोज करना है, बस पहिया को सुदृढ़ करने के लिए समय बर्बाद करना है।
विटालि इसेंको

1
क्या मैं यह सही देख रहा हूँ? 10 साल बाद एक भी वैध कार्यात्मक उत्तर नहीं? हो सकता है कि हमें समाधान के लिए एक और इनाम की आवश्यकता हो, जिसमें 75 नंबर $ log2 (75!) = 364 $ के साथ सूची में फेरबदल करने के लिए आवश्यक एन्ट्रापी की मात्रा का पता हो और हम इसे कैसे प्राप्त कर सकते हैं। एक फिशर-येट्स फेरबदल के दौरान एक बार क्रिप्टोग्राफिक रूप से सुरक्षित RNG को 256 बिट्स के साथ सुरक्षित करने की आवश्यकता होगी।
फाल्को

1
और अगर सामान्य कोडर इस समस्या को हल नहीं कर सकता है, तो क्या हम सभी एक ही 0.01% संभावित सॉलिटेयर गेम हमेशा के लिए खेल रहे हैं?
फाल्को

जवाबों:


1135

फिशर-येट्स के फेरबदल के(I)List आधार पर विस्तार पद्धति के साथ किसी भी तरह का फेरबदल करें :

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;  
    }  
}

उपयोग:

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

उपरोक्त कोड स्वैप उम्मीदवारों का चयन करने के लिए बहुत आलोचना की गई System.Random विधि का उपयोग करता है। यह तेज़ है लेकिन उतना यादृच्छिक नहीं है जितना इसे होना चाहिए। यदि आपको अपने फेरबदल में यादृच्छिकता की बेहतर गुणवत्ता की आवश्यकता है तो System.Security.Cryptography में यादृच्छिक संख्या जनरेटर का उपयोग करें:

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;
    }
}

इस ब्लॉग (WayBack Machine) पर एक सरल तुलना उपलब्ध है ।

संपादित करें: दो साल पहले इस जवाब को लिखने के बाद से, मेरी तुलना में बड़ी मूर्खतापूर्ण दोष को इंगित करने के लिए, कई लोगों ने टिप्पणी की है या मुझे लिखा है। वे बिल्कुल सही हैं। अगर यह उस तरह से इस्तेमाल किया गया है, तो System.Random में कुछ भी गलत नहीं है। उपरोक्त मेरे पहले उदाहरण में, मैं शफ़ल विधि के अंदर आरएनजी चर को तुरंत हटा देता हूं, जो कि विधि को बार-बार कहा जा रहा है, तो परेशानी पूछ रहा है। नीचे एक निश्चित, पूर्ण उदाहरण दिया गया है, जो कि एसओ पर आज यहां @ वेस्टन से प्राप्त एक उपयोगी टिप्पणी है।

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
क्या होगा अगर सूची। बाइट> बाइट.मैक्सवैल्यू है? यदि n = 1000, तो 255/1000 = 0 है, इसलिए डू लूप बॉक्स के बाद से एक अनंत लूप होगा [0] <0 हमेशा गलत है।
एंड्रयूज

18
मैं कहना चाहूंगा कि तुलना त्रुटिपूर्ण है। लूप में <कोड> नया रैंडम () </ कोड> का उपयोग करना समस्या है, न कि रैंडमनेस ऑफ <कोड> रैंडम </ कोड> स्पष्टीकरण
स्वेन

9
रैंडम से लेकर शफल विधि का एक उदाहरण पास करना एक अच्छा विचार है, बजाय इसके कि इसे अंदर बनाएं जैसे कि आप शफल को कई बार त्वरित उत्तराधिकार में बुला रहे हैं (उदाहरण के लिए बहुत सारी सूचियों में फेरबदल करना), सूचियों को सभी में फेरबदल किया जाएगा। रास्ता (उदाहरण के लिए पहला आइटम हमेशा स्थिति 3 में स्थानांतरित हो जाता है)।
मार्क हीथ

7
बस बनाने Random rng = new Random();के लिए एक staticतुलना पोस्ट में समस्या का समाधान होगा। जैसा कि प्रत्येक बाद की कॉल पिछले रैंडम अंतिम परिणाम से होती है।
पश्चिमोत्तर

5
# 2, यह स्पष्ट नहीं है कि क्रिप्टो जनरेटर के साथ संस्करण काम करता है क्योंकि बाइट की अधिकतम सीमा 255 है, इसलिए इससे बड़ी कोई भी सूची सही ढंग से फेरबदल नहीं करेगी।
मार्क सोउल

336

अगर हमें केवल एक पूरी तरह से यादृच्छिक क्रम में वस्तुओं को फेरबदल करने की आवश्यकता है (केवल एक सूची में वस्तुओं को मिलाने के लिए), तो मैं इस सरल अभी तक प्रभावी कोड को पसंद करता हूं जो गाइड द्वारा आइटम का आदेश देता है ...

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

40
GUIDs यादृच्छिक नहीं अद्वितीय होने के लिए होते हैं। इसका एक भाग मशीन-आधारित है और दूसरा भाग समय-आधारित और केवल एक छोटा भाग यादृच्छिक है। blogs.msdn.com/b/oldnewthing/archive/2008/06/27/8659071.aspx
Despertar

99
यह एक अच्छा सुरुचिपूर्ण समाधान है। यदि आप यादृच्छिकता उत्पन्न करने के लिए एक गाइड के अलावा कुछ और चाहते हैं, तो बस कुछ और द्वारा ऑर्डर करें। जैसे: var shuffledcards = cards.OrderBy(a => rng.Next()); compilr.com/grenade/sandbox/Program.cs
ग्रेनेड

20
कृपया नहीं। ये गलत है। "यादृच्छिक द्वारा आदेश देना" पूरी तरह से फेरबदल नहीं है: आप एक पूर्वाग्रह का परिचय देते हैं और इससे भी बदतर, आप अनंत छोरों में जाने का जोखिम उठाते हैं
वीटो डे टुलियो

77
@VitoDeTullio: आप गलत समझ रहे हैं। जब आप एक यादृच्छिक तुलना फ़ंक्शन प्रदान करते हैं, तो आप अनंत छोरों को जोखिम में डालते हैं ; एक सुसंगत कुल आदेश का उत्पादन करने के लिए एक तुलना फ़ंक्शन की आवश्यकता होती है । एक यादृच्छिक कुंजी ठीक है। यह सुझाव गलत है क्योंकि गाइड को यादृच्छिक होने की गारंटी नहीं है , इसलिए नहीं कि यादृच्छिक कुंजी द्वारा छंटाई की तकनीक गलत है।
एरिक लिपर्ट

24
@ डग: NewGuidकेवल इस बात की गारंटी देता है कि यह आपको एक अद्वितीय GUID प्रदान करता है। यह यादृच्छिकता के बारे में कोई गारंटी नहीं देता है। यदि आप एक अद्वितीय मूल्य बनाने के अलावा एक उद्देश्य के लिए एक GUID का उपयोग कर रहे हैं, तो आप इसे गलत कर रहे हैं।
एरिक लिपर्ट

120

मैं यहाँ इस सरल एल्गोरिथ्म के सभी क्लंकी संस्करणों से हैरान हूँ। फिशर-येट्स (या नथ शफल) थोड़ा मुश्किल है लेकिन बहुत कॉम्पैक्ट है। यह मुश्किल क्यों है? क्योंकि आपका ध्यान इस बात पर ध्यान देने की जरूरत है कि क्या आपका रैंडम नंबर जेनरेटर r(a,b)वैल्यू देता है, जहां bइंक्लूसिव या एक्सक्लूसिव है। मैंने विकिपीडिया विवरण को भी संपादित किया है ताकि लोग आँख बंद करके वहां छद्म कोड का पालन न करें और बग का पता लगाने के लिए कड़ी मेहनत करें। .Net के लिए, बिना आगे की हलचल के, बिना Random.Next(a,b)नंबर के अनन्य रिटर्न b, यहां बताया गया है कि इसे C # / नेट में कैसे लागू किया जा सकता है।

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;
}

इस कोड को आज़माएं


क्या rnd (i, list.Count) को rnd (0, list.Count) में बदलना बेहतर नहीं होगा ताकि किसी भी कार्ड को स्वैप किया जा सके?
डोनट्स

15
@ डोनट्स - नहीं। यदि आप ऐसा करते हैं तो आप फेरबदल में पूर्वाग्रह जोड़ देंगे।
शीतल शाह

2
स्वैप <T> को एक अलग विधि से अलग करने से, ऐसा लगता है जैसे आप अस्थायी के लिए बहुत सारे अनावश्यक टी आवंटन का कारण बनते हैं।
क्ले

2
मेरा तर्क है कि LINQ संभावित रूप से फेरबदल के प्रदर्शन को धीमा कर सकता है, और इसका उपयोग न करने का एक कारण होगा, विशेष रूप से कोड की सापेक्ष सादगी को देखते हुए।
विंग्लर २

7
जब i = list.Count - 1, यानी अंतिम पुनरावृत्ति, rnd.Next(i, list.Count)आपको वापस दे देगा। इसलिए आपको i < list.Count -1लूप की स्थिति की आवश्यकता है। ठीक है, आपको इसकी आवश्यकता नहीं है, लेकिन यह 1 पुनरावृत्ति को बचाता है;)
पॉड

78

IEnumerable के लिए एक्सटेंशन विधि:

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

3
ध्यान दें कि यह थ्रेड-सुरक्षित नहीं है, भले ही थ्रेड-सुरक्षित सूची पर उपयोग किया गया हो
BlueRaja - Danny Pflughoeft

1
हम इस फ़ंक्शन को सूची <string> कैसे देते हैं?
मॉन्स्टरमॉरपीजी

8
इस एल्गोरिथ्म के साथ दो महत्वपूर्ण समस्याएं हैं: - OrderByअपने (ओस्टेन्सिबल रूप से यादृच्छिक) कुंजी द्वारा आइटम को सॉर्ट करने के लिए क्विकॉर्ट वेरिएंट का उपयोग करता है। QuickSort प्रदर्शन ओ (एन लॉग एन) है ; इसके विपरीत, एक फिशर-येट्स फेरबदल हे (एन) है । 75 तत्वों के संग्रह के लिए, यह एक बड़ी बात नहीं हो सकती है, लेकिन बड़े संग्रह के लिए अंतर स्पष्ट हो जाएगा।
जॉन बेयर

10
... - Random.Next()मूल्यों का एक छद्म यादृच्छिक वितरण उत्पन्न कर सकता है, लेकिन यह गारंटी नहीं देता है कि मूल्य अद्वितीय होंगे। डुप्लिकेट कुंजियों की संभावना एन के साथ बढ़ती है (गैर-रैखिक रूप से) जब तक यह निश्चितता तक नहीं पहुंचता है जब एन 2 ^ 32 + 1 तक पहुंचता है। OrderByQuicksort एक है स्थिर प्रकार; इस प्रकार, यदि कई तत्वों को एक ही छद्म यादृच्छिक सूचकांक मान सौंपा जाता है, तो आउटपुट अनुक्रम में उनका क्रम इनपुट अनुक्रम के समान होगा ; इस प्रकार, एक पूर्वाग्रह को "फेरबदल" में पेश किया जाता है।
जॉन बेयर

27
@ जॉनबेयर: पूर्वाग्रह के स्रोत से कहीं अधिक बड़ी समस्याएं हैं। रैंडम के लिए केवल चार बिलियन संभव बीज हैं, जो दूर है, मध्यम आकार के सेट के संभावित फेरबदल की संख्या से काफी कम है। संभव फेरबदल का केवल एक छोटा सा अंश उत्पन्न किया जा सकता है। वह पक्षपात आकस्मिक टक्करों के कारण पूर्वाग्रह को बौना कर देता है।
एरिक लिपर्ट

14

आइडिया को आइटम और रैंडम ऑर्डर के साथ बेनामी ऑब्जेक्ट मिलता है और फिर इस ऑर्डर और रिटर्न वैल्यू द्वारा आइटम्स को रीऑर्डर किया जाता है:

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

2
सर्वश्रेष्ठ एक लाइनर समाधान
vipin8169

1
आपको अंतिम
फी

यदि कोई व्यक्ति rnd के बारे में अनिश्चित है, तो उसे रैंडम rnd = new random () से ऊपर कोड में जोड़ें;
ग्रेग ट्रेवेलिक

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()जो आने वाली सूची से सभी वस्तुओं को हटाने से बचें? मैं वास्तव में यह नहीं देखता कि आप उन सूचियों को खाली क्यों करना चाहते हैं।
क्रिस मैरिसिक

9

संपादित करेंRemoveAt मेरे पिछले संस्करण में एक कमजोरी है। यह समाधान उस पर काबू पा लेता है।

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];
    }
}

वैकल्पिक पर ध्यान दें Random generator, यदि Randomआपकी आवश्यकताओं के लिए आधार ढांचा कार्यान्वयन थ्रेड-सुरक्षित या क्रिप्टोग्राफिक रूप से पर्याप्त मजबूत नहीं है, तो आप अपने कार्यान्वयन को ऑपरेशन में इंजेक्ट कर सकते हैं।

Randomइस उत्तर में थ्रेड-सेफ क्रिप्टोग्राफिक रूप से मजबूत कार्यान्वयन के लिए एक उपयुक्त कार्यान्वयन पाया जा सकता है।


यहाँ एक विचार है, IList को (उम्मीद के मुताबिक) कुशल तरीके से विस्तारित करें।

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]];
}


Stackoverflow.com/questions/4412405/… देखें । आपको पहले से ही पता होना चाहिए।
नवफाल

@ नवाफ मेरा बेहतर क्रियान्वयन देखते हैं।
जोर्डेल

1
हम्म फेयर काफी यह है GetNextया Next?
नवाफल

4

आप यह प्राप्त कर सकते हैं कि इस सरल विस्तार विधि का उपयोग करें

public static class IEnumerableExtensions
{

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

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

और आप निम्न कार्य करके इसका उपयोग कर सकते हैं

// 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
मैं Randomफ़ंक्शन के बाहर वर्ग उदाहरण को एक staticचर के रूप में रखूंगा। अन्यथा आप टाइमर से एक ही यादृच्छिककरण बीज प्राप्त कर सकते हैं यदि त्वरित उत्तराधिकार में कहा जाता है।
लेमनड

एक दिलचस्प नोट - यदि आप एक लूप के भीतर रैंडम क्लास को तेजी से इंस्टेंट करते हैं, तो प्रत्येक एमएस के 0 एमएस और 200 एमएस के बीच में कहें, तो आपके पास एक ही यादृच्छिककरण बीज प्राप्त करने का बहुत अधिक मौका है - जिसके परिणामस्वरूप परिणाम दोहराते हैं। हालाँकि आप इसे रैंडम रैंड = नए रैंडम (गाइड.न्यूजीयूड ()। गेटहैशकोड ()) के माध्यम से प्राप्त कर सकते हैं; यह प्रभावी रूप से रेंडमाइजेशन को गाइड से प्राप्त करने के लिए मजबूर करता है। न्यूगाइड ()
बालेओस

4

यह फेरबदल का मेरा पसंदीदा तरीका है जब मूल को संशोधित नहीं करना वांछनीय है। यह फिशर-येट्स के "इनसाइड-आउट" एल्गोरिथ्म का एक प्रकार है जो किसी भी अनुक्रम योग्य अनुक्रम पर काम करता है (लंबाई sourceको शुरू से ज्ञात करने की आवश्यकता नहीं है)।

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;
}

से लेकर एक रेंज आवंटित करके भी इस एल्गोरिथ्म को लागू किया जा सकता 0हैlength - 1 को अंतिम इंडेक्स के साथ यादृच्छिक रूप से चुने गए इंडेक्स को स्वैप करके और इंडेक्स जब तक कि सभी इंडेक्स बिल्कुल एक बार नहीं चुने गए हों। यह उपरोक्त कोड सटीक समान चीज़ को पूरा करता है, लेकिन अतिरिक्त आवंटन के बिना। जो काफी साफ सुथरा हो।

Randomवर्ग के संबंध में यह एक सामान्य उद्देश्य संख्या जनरेटर है (और अगर मैं एक लॉटरी चला रहा था तो मैं कुछ अलग का उपयोग करने पर विचार करूंगा)। यह डिफ़ॉल्ट रूप से समय आधारित बीज मूल्य पर भी निर्भर करता है। समस्या का एक छोटा सा दोष यह है कि आप Randomकक्षा को बीज के साथ जोड़ RNGCryptoServiceProviderसकते हैं या आप RNGCryptoServiceProviderएक समान विधि का उपयोग कर सकते हैं (नीचे देखें) समान रूप से चुने गए यादृच्छिक डबल फ्लोटिंग पॉइंट मान उत्पन्न करने के लिए लेकिन लॉटरी चलाने के लिए बहुत अधिक यादृच्छिकता और प्रकृति की समझ की आवश्यकता होती है। यादृच्छिकता स्रोत।

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

एक यादृच्छिक डबल उत्पन्न करने के लिए (0 और 1 के बीच विशेष रूप से) एक पूर्णांक समाधान के पैमाने का उपयोग करना है। यदि आपको एक यादृच्छिक डबल के आधार पर सूची से कुछ लेने की जरूरत है xजो हमेशा होने वाला 0 <= x && x < 1है तो सीधे आगे है।

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

का आनंद लें!


4

यदि आप दो का उपयोग करने में कोई आपत्ति नहीं करते हैं Lists, तो यह शायद इसे करने का सबसे आसान तरीका है, लेकिन शायद सबसे कुशल या अप्रत्याशित नहीं है:

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

यदि आपके पास एक निश्चित संख्या (75) है, तो आप 75 तत्वों के साथ एक सरणी बना सकते हैं, फिर अपनी सूची की गणना करें, तत्वों को सरणी में यादृच्छिक पदों पर ले जाएं। आप फिशर-येट्स फेरबदल का उपयोग करके सूची संख्या को सरणी इंडेक्स में मैप कर सकते हैं ।


3

मैं आमतौर पर उपयोग करता हूं:

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 एक O (n) ऑपरेशन है, जो इस कार्यान्वयन को निषेधात्मक रूप से धीमा बनाता है।
जॉर्ज पोलेवॉय

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

यहाँ एक कुशल शफलर है जो फेरबदल के मूल्यों की बाइट देता है। यह कभी ज़रूरत से ज़्यादा फेरबदल नहीं करता है। इसे वहीं से फिर से शुरू किया जा सकता है, जहां इसे पहले छोड़ा गया था। मेरा वास्तविक कार्यान्वयन (दिखाया नहीं गया) एक MEF घटक है जो उपयोगकर्ता को निर्दिष्ट प्रतिस्थापन फेरबदल की अनुमति देता है।

    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

यह करने के लिए एक धागा-सुरक्षित तरीका है:

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
ढेर अतिप्रवाह में आपका स्वागत है! कृपया कोड के एक विशाल ब्लॉक के बजाय अपने उत्तर में कुछ स्पष्टीकरण जोड़ने पर विचार करें। यहां हमारा लक्ष्य लोगों को शिक्षित करना है ताकि वे उत्तर को समझ सकें और इसे अन्य स्थितियों में लागू कर सकें। यदि आप अपना कोड टिप्पणी करते हैं और एक स्पष्टीकरण जोड़ते हैं, तो आप अपने उत्तर को उस व्यक्ति से न केवल मददगार बनेंगे, जिसने इस बार प्रश्न पूछा है, बल्कि भविष्य में किसी को भी, जो एक ही समस्या हो सकती है।
सितारों का अधिशेष

4
इस कोड का अधिकांश सवाल पूरी तरह से अप्रासंगिक है, और केवल उपयोगी हिस्सा मूल रूप से लगभग 6 साल पहले एडम टेगेन के जवाब को दोहराता है।
टीसी

0

स्वीकृत उत्तर का एक सरल संशोधन जो काम करने की जगह एक नई सूची देता है, और अधिक सामान्य 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

यकीन के लिए पुरानी पोस्ट, लेकिन मैं सिर्फ एक GUID का उपयोग करता हूं।

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

एक GUID हमेशा अनोखा होता है, और चूंकि यह हर बार पुनर्जीवित होता है, इसलिए परिणाम हर बार बदलता है।


कॉम्पैक्ट, लेकिन क्या आपके पास उच्च गुणवत्ता वाले यादृच्छिक होने के लिए लगातार newGuids की छंटाई पर एक संदर्भ है? क्विड / यूआईडी के कुछ संस्करणों में समय टिकट और अन्य गैर-यादृच्छिक भाग होते हैं।
जोहान लुंडबर्ग

8
यह उत्तर पहले ही दिया जा चुका है, और इससे भी बदतर विशिष्टता के लिए डिज़ाइन किया गया है।
एलेक्स एंगस

-7

इस तरह की समस्या के लिए एक बहुत ही सरल दृष्टिकोण सूची में कई यादृच्छिक तत्व स्वैप का उपयोग करना है।

छद्म कोड में यह इस तरह दिखेगा:

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

1
इस दृष्टिकोण के साथ एक समस्या यह है कि कब रोकना है। यह छद्म यादृच्छिक संख्या जनरेटर में किसी भी पूर्वाग्रह को अतिरंजित करने की प्रवृत्ति भी है।
मार्क बेसे 19

3
हाँ। अत्यधिक अकुशल। इस तरह से एक दृष्टिकोण का उपयोग करने का कोई कारण नहीं है जब बेहतर, तेज दृष्टिकोण मौजूद होते हैं जो बस के रूप में सरल होते हैं।
पीटरअलेनवेब

1
बहुत कुशल या प्रभावी नहीं ... इसे चलाने से N समय की संभावना होगी कि वे अपनी मूल स्थिति में कई तत्वों को छोड़ दें।
एनएसजोनस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.