ලැයිස්තුවක් අහඹු කරන්න <T>


885

C # හි සාමාන්‍ය ලැයිස්තුවක අනුපිළිවෙල අහඹු ලෙස කිරීමට හොඳම ක්‍රමය කුමක්ද? ලොතරැයි වර්ගයේ යෙදුමක් සඳහා ඒවා ඇද ගැනීම සඳහා අහඹු ඇණවුමක් ලබා දීමට මා කැමති ලැයිස්තුවක සීමිත අංක 75 ක කට්ටලයක් මා සතුව ඇත.



5
පහත සඳහන් ෆිෂර්-යේට්ස් ඇල්ගොරිතම භාවිතා කරමින් IList <T> සහ IEnumerable <T> මාරු කිරීම සඳහා දිගු කිරීමේ ක්‍රම අඩංගු මෙම NuGet පැකේජය ගැන ඔබ උනන්දු විය හැකිය
ChaseMedallion

3
At නටාන් ඔවුන් මෙම ප්‍රශ්නය වසා දැමුවේ යමෙකු “බොහෝ ව්‍යාපෘතිවල වැඩ කර පුස්තකාල බොහොමයක් සංවර්ධනය කර ඇති අතර කිසි විටෙකත් එවැනි ක්‍රමවේදයක අවශ්‍යතාවයක් නොතිබූ” නිසාය. දැන් අප අප ගැනම සොයා බැලිය යුතුය, හොඳම ක්‍රියාත්මක කිරීම් සෙවීම, රෝදය ප්‍රතිනිර්මාණය කිරීම සඳහා කාලය නාස්ති කිරීම.
විටාලි අයිසෙන්කෝ

1
මම මේ අයිතිය දකිනවාද? වසර 10 කට පසු එක වලංගු ක්‍රියාකාරී පිළිතුරක් නොවේද? $ Log2 (75!) = 364 numbers අංක 75 ක් සහිත ලැයිස්තුවක් මාරු කිරීමට සහ අපට මෙය ලබා ගත හැකි ආකාරය සඳහා අවශ්‍ය එන්ට්‍රොපි ප්‍රමාණය ආමන්ත්‍රණය කරන විසඳුමක් සඳහා අපට තවත් ත්‍යාගයක් අවශ්‍ය විය හැකිය. ධීවර යාත්රා මාරුවීමේදී අවම වශයෙන් එක් වරක්වත් එන්ට්‍රොපි බිටු 256 ක් සහිත ගුප්ත විද්‍යාත්මකව ආරක්‍ෂිත ආර්එන්ජී එකක් නැවත බැලීමට යමෙකුට අවශ්‍ය වේ.
ෆැල්කෝ

1
සුපුරුදු කෝඩරයට මෙම ගැටළුව විසඳිය නොහැකි නම්, අප සියලු දෙනාම එකම සොලිටෙයාර් ක්‍රීඩා වලින් 0.01% ක්ම සදහටම ක්‍රීඩා කර තිබේද?
ෆැල්කෝ

Answers:


1165

ෆිෂර්-යේට්ස් මාරුව(I)List මත පදනම්ව දීර් extension කිරීමේ ක්‍රමයක් සමඟ ඕනෑම දෙයක් මාරු කරන්න :

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();

Swap අපේක්ෂකයින් තෝරා ගැනීම සඳහා ඉහත කේතය බොහෝ විවේචනයට ලක්වූ 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;
    }
}

සරල සැසඳීමක් මෙම බ්ලොග් අඩවියෙන් ලබා ගත හැකිය (වේබැක් යන්ත්‍රය).

සංස්කරණය කරන්න: මීට වසර කිහිපයකට පෙර මෙම පිළිතුර ලිවූ දා සිට, මගේ සංසන්දනයේ ඇති විශාල මෝඩ දෝෂය පෙන්වා දීමට බොහෝ අය මට අදහස් දැක්වීය. ඒවා ඇත්තෙන්ම හරි. System.Random එය අදහස් කළ ආකාරයට භාවිතා කරන්නේ නම් එහි කිසිදු වරදක් නොමැත. ඉහත මගේ පළමු උදාහරණයේ දී, මම ෂෆල් ක්‍රමයේ ඇතුළත rng විචල්‍යය ක්ෂණිකව ස්ථාපනය කරමි, එය නැවත නැවත කැඳවීමට යන්නේ නම් කරදරයක් ඉල්ලා සිටී. පහත දැක්වෙන්නේ අද දින වෙස්ටන් වෙතින් SO හි ලැබුණු සැබවින්ම ප්‍රයෝජනවත් අදහස් දැක්වීමක් මත පදනම් වූ ස්ථාවර, සම්පූර්ණ උදාහරණයකි.

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

32
ලැයිස්තුව නම් කුමක් ද? බයිට්.මැක්ස් අගය යනු කුමක්ද? N = 1000 නම්, 255/1000 = 0, එබැවින් ඩූ ලූප් අසීමිත ලූපයක් වනු ඇත [0] <0 කොටුව සැමවිටම අසත්‍යය.
ඇන්ඩ rew ස්

18
සංසන්දනය දෝෂ සහිත බව මම පෙන්වා දීමට කැමැත්තෙමි. <code> නව සසම්භාවී () </code> ලූපයක් භාවිතා කිරීම ගැටළුව මිස <code> සසම්භාවී </ code> පැහැදිලි කිරීම
Sven

9
අහඹු සිදුවීමක් ඇතුලත නිර්මාණය කරනවාට වඩා එය ඇතුළත නිර්මාණය කරනවාට වඩා හොඳ අදහසක් නම්, ඔබ ඉක්මන් අනුපිළිවෙලින් බොහෝ වාරයක් ෂෆල් අමතන්නේ නම් (උදා: කෙටි ලැයිස්තු විශාල ප්‍රමාණයක් මාරු කිරීම), ලැයිස්තු සියල්ලම එකම ආකාරයකින් මාරු වනු ඇත මාර්ගය (උදා: පළමු අයිතමය සෑම විටම 3 වන ස්ථානයට ගෙන යනු ලැබේ).
මාර්ක් හීත්

7
සංසන්දනය කිරීමේ පෝස්ට් එකේ ගැටලුව විසඳීම පමණක් සිදු Random rng = new Random();කරයි static. එක් එක් පසු ඇමතුම පෙර ඇමතුම් වලින් ලැබෙන බැවින් අවසාන අහඹු ප්‍රති .ලය.
වෙස්ටන්

5
# 2, ක්‍රිප්ටෝ උත්පාදක යන්ත්රය සමඟ අනුවාදය ක්‍රියා කරන බව පැහැදිලි නැත, මන්ද බයිට් එකක උපරිම පරාසය 255 වන බැවින් ඊට වඩා විශාල ලැයිස්තුවක් නිවැරදිව වෙනස් නොවේ.
මාර්ක් සොවුල්

348

අපට අවශ්‍ය වන්නේ අයිතම සම්පුර්ණයෙන්ම අහඹු පිළිවෙලකට මාරු කිරීමට නම් (ලැයිස්තුවේ ඇති අයිතම මිශ්‍ර කිරීමට පමණි), මම කැමති මෙම සරල නමුත් effective ලදායී කේතයට මග පෙන්වීමෙන් භාණ්ඩ ඇණවුම් කරන ...

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

42
GUIDs යනු අහඹු ලෙස අද්විතීය නොවේ. එයින් කොටසක් යන්ත්‍ර මත පදනම් වූ අතර තවත් කොටසක් කාලය මත පදනම් වූ අතර අහඹු ලෙස ඇත්තේ සුළු කොටසක් පමණි. blogs.msdn.com/b/oldnewthing/archive/2008/06/27/8659071.aspx
ඩෙස්පර්ටාර්

103
මෙය කදිම අලංකාර විසඳුමක්. අහඹු ලෙස උත්පාදනය කිරීම සඳහා මාර්ගෝපදේශයක් හැර වෙනත් දෙයක් ඔබට අවශ්‍ය නම්, වෙනත් දෙයකින් ඇණවුම් කරන්න. උදා: var shuffledcards = cards.OrderBy(a => rng.Next()); compilr.com/grenade/sandbox/Program.cs
අත්බෝම්බය

20
කරුණාකර නැත. මේක වැරදියි. "අහඹු ලෙස ඇණවුම් කිරීම" මුළුමනින්ම වෙනස් කිරීමක් නොවේ: ඔබ පක්ෂග්‍රාහී බවක් හඳුන්වා දෙන අතර, වඩාත් නරක නම්, ඔබ අසීමිත වළළු
තුළට

81
ItVitoDeTullio: ඔබ වැරදියට තේරුම් ගන්නවා. ඔබ අහඹු සංසන්දනාත්මක ශ්‍රිතයක් සපයන විට ඔබ අනන්ත ලූප අවදානමට ලක් කරයි ; ස්ථාවර සම්පූර්ණ අනුපිළිවෙලක් නිෂ්පාදනය කිරීම සඳහා සංසන්දනාත්මක ශ්‍රිතයක් අවශ්‍ය වේ . අහඹු යතුරක් හොඳයි. මෙම යෝජනාව වැරදියි, මාර්ගෝපදේශ අහඹු ලෙස සහතික නොවන නිසා මිස අහඹු යතුරකින් වර්ග කිරීමේ තාක්ෂණය වැරදි නිසා නොවේ .
එරික් ලිපර්ට්

26
Og ඩග්: NewGuidඑය ඔබට අද්විතීය GUID ලබා දෙන බවට සහතික කරයි. එය අහඹු බව පිළිබඳ සහතිකයක් ලබා නොදේ. අද්විතීය අගයක් නිර්මාණය කිරීම හැර වෙනත් අරමුණක් සඳහා ඔබ GUID භාවිතා කරන්නේ නම් , ඔබ එය වැරදිය.
එරික් ලිපර්ට්

122

මෙම සරල ඇල්ගොරිතමයේ සියලුම අපැහැදිලි අනුවාදයන් ගැන මම ටිකක් පුදුම වෙමි. ෆිෂර්-යේට්ස් (හෝ නුත් ෂෆල්) ටිකක් උපක්‍රමශීලී නමුත් ඉතා සංයුක්තයි. එය ව්‍යාකූල ඇයි? ඔබගේ අහඹු සංඛ්‍යා උත්පාදක යන්ත්රය ඇතුළත් කළ හෝ සුවිශේෂී වූ r(a,b)තැනක වටිනාකම නැවත ලබා දෙන්නේද යන්න පිළිබඳව ඔබේ අවධානය යොමු කළ යුතු බැවිනි b. මම විකිපීඩියා විස්තරය ද සංස්කරණය කර ඇති බැවින් මිනිසුන් එහි ව්‍යාජ කේතය අන්ධ ලෙස අනුගමනය නොකරන අතර දෝෂ හඳුනා ගැනීමට අපහසු වේ. .Net සඳහා, වැඩි විස්තරයකින් තොරව Random.Next(a,b)ප්‍රතිලාභ අංකය b, එය C # /. Net තුළ ක්‍රියාත්මක කළ හැකි ආකාරය මෙන්න.

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

මෙම කේතය උත්සාහ කරන්න .


16
On ඩොනට්ස් - නැත. ඔබ එසේ කළහොත් ඔබ මාරුවීමේදී පක්ෂග්‍රාහී බවක් එක් කරයි.
ෂිටාල් ෂා

2
Swap <T> වෙනම ක්‍රමයකට වෙන් කිරීමෙන්, ඔබ තාවකාලික සඳහා අනවශ්‍ය ටී ප්‍රතිපාදන විශාල ප්‍රමාණයක් ඇති කරන බවක් පෙනේ.
මැටි

2
මම තර්ක කරන්නේ LINQ මගින් මාරුවීමේ ක්‍රියාකාරිත්වය මන්දගාමී විය හැකි අතර එය භාවිතා නොකිරීමට එය හේතුවක් වනු ඇත, විශේෂයෙන් කේතයේ සාපේක්ෂ සරල බව සැලකිල්ලට ගෙන.
එලියානෝරා

7
කවදාද i = list.Count - 1, එනම් අවසාන පුනරාවර්තනය rnd.Next(i, list.Count)ඔබට නැවත ලබා දෙනු ඇත. එබැවින් ඔබට i < list.Count -1ලූප් කොන්දේසිය ලෙස අවශ්‍ය වේ. හොඳයි, ඔබට එය 'අවශ්‍ය නැත', නමුත් එය 1 පුනරාවර්තනයක් ඉතිරි කරයි;)
පොඩ්

2
මෙම කේතය අපේක්ෂිත පරිදි ක්‍රියා නොකරයි. අවසාන අංකය සෑම විටම 0හෝ list.Count-1.
ඔනිරෝස්

80

IEnumerable සඳහා දිගු කිරීමේ ක්‍රමය:

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

3
නූල්-ආරක්ෂිත ලැයිස්තුවක භාවිතා කළත් මෙය නූල්-ආරක්ෂිත නොවන බව සලකන්න
බ්ලූරාජා - ඩැනී ප්ලග්ගෝෆ්ට්

8
මෙම ඇල්ගොරිතමයේ සැලකිය යුතු ගැටළු දෙකක් තිබේ: - OrderByඅයිතම ඒවායේ (පෙනෙන ලෙස අහඹු) යතුරු මගින් වර්ග කිරීමට ක්වික්සෝර්ට් ප්‍රභේදයක් භාවිතා කරයි. ක්වික්සෝර්ට් කාර්ය සාධනය ඕ (එන් ලොග් එන්) ; ඊට වෙනස්ව, ෆිෂර්-යේට්ස් මාරුව O (N) වේ. මූලද්රව්ය 75 ක එකතුවක් සඳහා, මෙය විශාල ගනුදෙනුවක් නොවිය හැකි නමුත් විශාල එකතු සඳහා වෙනස පැහැදිලි වනු ඇත.
ජෝන් බෙයර්

10
... - Random.Next()සාධාරණ ලෙස සසම්භාවී සාරධර්ම බෙදා හැරීමක් ඇති කළ හැකි නමුත් අගයන් අද්විතීය වනු ඇති බවට එය සහතික නොවේ . N 2 ^ 32 + 1 කරා ළඟා වන විට එය නිශ්චිතභාවයට පත්වන තෙක් N සමඟ අනුපිටපත් යතුරු වල සම්භාවිතාව (රේඛීය නොවන) වර්ධනය වේ. මෙම QuickSort යනු ස්ථාවර ආකාරයක; මේ අනුව, බහු මූලද්රව්ය එකම ව්යාජ සසම්භාවී දර්ශකය අගය පවරා ගැනීමට සිදු නම්, ප්රතිදානය අනුක්රමය ඔවුන්ගේ නියෝගය වනු ඇත එම යෙදවුම් අනුපිළිවෙල දී මෙන්, මේ අනුව, නැඹුරුවක් "මාරු කිරීම" තුළට හඳුන්වා දෙනු ලැබේ. OrderBy
ජෝන් බෙයර්

28
@ ජෝන්බයර්: එම පක්ෂග්‍රාහී ප්‍රභවයට වඩා බොහෝ විශාල ගැටළු තිබේ. සසම්භාවී බීජ සඳහා බීජ ඇත්තේ බිලියන හතරක් පමණි, එය මධ්‍යස්ථ ප්‍රමාණයේ කට්ටලයක ඇති විය හැකි මාර්‍ග ගණනට වඩා බෙහෙවින් අඩුය. ජනනය කළ හැක්කේ ඉතා සුළු ප්‍රමාණයක් පමණි. අහඹු ගැටුම් හේතුවෙන් එම නැඹුරුව පක්ෂග්‍රාහී වේ.
එරික් ලිපර්ට්

17

අදහස යනු අයිතමය සහ අහඹු අනුපිළිවෙල සමඟ නිර්නාමික වස්තුවක් ලබාගෙන පසුව මෙම ඇණවුම සහ ප්‍රතිලාභ අගය අනුව අයිතම නැවත සකසන්න:

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

4
හොඳම එක් ලයිනර් විසඳුම
vipin8169

2
ඔබට අවසානයෙහි අර්ධ සළකුණක් මග හැරී ඇත fyi
reggaeguitar

Rnd ගැන යමෙකුට සැක සහිත නම්, ඉහත කේතයට පෙර මෙය එකතු කරන්න අහඹු rnd = නව සසම්භාවී ();
ග්‍රෙග් ට්‍රෙවලික්

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/… බලන්න . ඔබ දැනටමත් දැනුවත් විය යුතුය.
nawfal

වැඩිදියුණු කළ ක්‍රියාවට නැංවීම බලන්න.
ජොඩ්රෙල්

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 ms සහ 200 ms අතර කියන්න, එවිට ඔබට එකම සසම්භාවීකරණ බීජයක් ලබා ගැනීමට ඉතා ඉහළ අවස්ථාවක් තිබේ - එමඟින් ප්‍රති results ල පුනරාවර්තනය වේ. කෙසේ වෙතත් ඔබට සසම්භාවී rand = නව සසම්භාවී (Guid.NewGuid () භාවිතා කර මෙය ලබා ගත හැකිය. GetHashCode ()); මෙය අහඹු ලෙස මාර්ගෝපදේශයෙන් ව්‍යුත්පන්න කිරීමට බල කරයි. නිව්ගුයිඩ් ()
බාලියෝස්

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
තොග පිටාර ගැලීම වෙත සාදරයෙන් පිළිගනිමු! විශාල කේත සමූහයකට වඩා කරුණාකර ඔබේ පිළිතුරට යම් පැහැදිලි කිරීමක් එක් කිරීම ගැන සලකා බලන්න. මෙහි අපගේ පරමාර්ථය වන්නේ මිනිසුන් දැනුවත් කිරීම සහ ඔවුන්ට වෙනත් අවස්ථාවන්හිදී එය අදාළ කර ගත හැකි වන පරිදි ඔවුන්ව දැනුවත් කිරීමයි. ඔබ ඔබේ කේතය අදහස් දක්වමින් පැහැදිලි කිරීමක් එකතු කරන්නේ නම්, ඔබ ඔබේ පිළිතුර මෙවර ප්‍රශ්නය ඇසූ පුද්ගලයාට පමණක් නොව අනාගතයේ දී එකම ගැටලුවක් ඇති ඕනෑම කෙනෙකුට ප්‍රයෝජනවත් වනු ඇත.
starplusplus

4
මෙම කේතය බොහෝමයක් ප්‍රශ්නයට මුළුමනින්ම අදාල නොවන අතර එකම ප්‍රයෝජනවත් කොටස මූලික වශයෙන් ඇඩම් ටෙගන්ගේ පිළිතුර වසර 6 කට පමණ පෙර සිට පුනරාවර්තනය වේ.
TC

0

පිළිබඳ සරල වෙනස් පිළිගත් පිළිතුර වෙනුවට දී-ස්ථානය වැඩ නව ලැයිස්තුව නැවත, සහ වඩා පොදු පිළිගන්නා IEnumerable<T>තවත් බොහෝ Linq ක්රම මෙන්.

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


0

නැවත පැමිණීමට අවශ්‍ය මූලද්‍රව්‍ය ගණන නියම කිරීමට ඉඩ සලසන ෆිෂර්-යේට්ස් මාරුව ක්‍රියාත්මක කිරීම මෙන්න; එබැවින්, ඔබ අපේක්ෂිත මූලද්‍රව්‍ය ගණන ගැනීමට පෙර මුලින්ම සම්පූර්ණ එකතුව වර්ග කිරීම අවශ්‍ය නොවේ.

හුවමාරු මූලද්‍රව්‍යවල අනුක්‍රමය පෙරනිමියෙන් ආපසු හරවනු ලැබේ; පළමු මූලද්‍රව්‍යයේ සිට අවසාන මූලද්‍රව්‍යය දක්වා ඉදිරියට යන අතර එමඟින් එකතුවේ උප කුලකයක් ලබා ගැනීමෙන් සමස්ත එකතුවම මාරු කිරීමේ සමාන (අර්ධ) අනුක්‍රමය ලැබේ:

collection.TakeRandom(5).SequenceEqual(collection.Shuffle().Take(5)); // true

මෙම ඇල්ගොරිතම පදනම් වී ඇත්තේ ඩර්ස්ටන්ෆෙල්ඩ්ගේ (නවීන) විකිපීඩියාවේ ෆිෂර්-යේට්ස් මාරුවෙහි අනුවාදය මත ය.

public static IList<T> TakeRandom<T>(this IEnumerable<T> collection, int count, Random random) => shuffle(collection, count, random);
public static IList<T> Shuffle<T>(this IEnumerable<T> collection, Random random) => shuffle(collection, null, random);
private static IList<T> shuffle<T>(IEnumerable<T> collection, int? take, Random random)
{
    var a = collection.ToArray();
    var n = a.Length;
    if (take <= 0 || take > n) throw new ArgumentException("Invalid number of elements to return.");
    var end = take ?? n;
    for (int i = 0; i < end; i++)
    {
        var j = random.Next(i, n);
        (a[i], a[j]) = (a[j], a[i]);
    }

    if (take.HasValue) return new ArraySegment<T>(a, 0, take.Value);
    return a;
}

0

ඔබේ ප්‍රශ්නය වන්නේ ලැයිස්තුවක් අහඹු ලෙස සකසන්නේ කෙසේද යන්නයි . මෙයින් අදහස් වන්නේ:

  1. සියලු අද්විතීය සංයෝජන සිදුවිය හැකි විය යුතුය
  2. සියලුම අද්විතීය සංයෝජන එකම බෙදාහැරීමකින් සිදුවිය යුතුය (AKA පක්ෂග්‍රාහී නොවන).

මෙම ප්‍රශ්නය සඳහා පළ කර ඇති පිළිතුරු විශාල සංඛ්‍යාවක් “අහඹු” වීම සඳහා ඉහත අවශ්‍යතා දෙක සපුරාලන්නේ නැත.

ෆිෂර්-යේට්ස් මාරු කිරීමේ ක්‍රමය අනුගමනය කරන සංයුක්ත, පක්ෂග්‍රාහී නොවන ව්‍යාජ අහඹු ශ්‍රිතයක් මෙන්න.

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

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

පළමු අවශ්‍යතාවය අවම වශයෙන් මාරු කිරීමේ ක්‍රමය මත රඳා පවතින තරමට PRNG (හෝ වෙනත් RNG) මත රඳා පවතින බව සලකන්න. උදාහරණයක් ලෙස, PRNG හි කාල සීමාව ලැයිස්තුවේ ඇති ප්‍රේරක ගණනට වඩා අඩු නම්, PRNG හට තෝරා ගත නොහැකි සමහර ප්‍රේරණයන් තිබේ. (මෙය සමහර යෙදුම් සඳහා සහ ප්‍රමාණවත් තරම් විශාල ලැයිස්තුවක් සඳහා, සියලු ප්‍රේරණයන්ගෙන් තෝරා ගැනීමට වඩා අහඹු ලෙස ක්‍රියා කිරීම සාමාන්‍යයෙන් වැදගත් වේ.)
පීටර් ඕ.

0

IComparer<T>සහ භාවිතා කරමින් ප්‍රභේදයක් යෝජනා කිරීමට අවශ්‍ය වූයේ List.Sort():

public class RandomIntComparer : IComparer<int>
{
    private readonly Random _random = new Random();
    
    public int Compare(int x, int y)
    {
        return _random.Next(-1, 2);
    }
}

භාවිතය:

list.Sort(new RandomIntComparer());

-5

පැරණි පෝස්ට් නිසැකවම, නමුත් මම භාවිතා කරන්නේ GUID ය.

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

GUID සෑම විටම අද්විතීය වන අතර, එය ප්‍රතිනිර්මාණය වන සෑම අවස්ථාවකම ප්‍රති result ලය වෙනස් වේ.


සංයුක්ත, නමුත් උසස් තත්ත්වයේ අහඹු ලෙස අඛණ්ඩව නව මාර්ගෝපදේශ වර්ග කිරීම පිළිබඳව ඔබට සඳහනක් තිබේද? Quid / uuid හි සමහර අනුවාද වල කාල මුද්දර සහ වෙනත් අහඹු නොවන කොටස් ඇත.
ජොහාන් ලුන්ඩ්බර්ග්

9
මෙම පිළිතුර දැනටමත් ලබා දී ඇති අතර වඩාත් නරක ලෙස එය නිර්මාණය කර ඇත්තේ අහඹු ලෙස නොව අද්විතීය භාවය සඳහා ය.
ඇලෙක්ස් අංගස්

-7

මේ ආකාරයේ ගැටළුවකට ඉතා සරල ප්‍රවේශයක් වන්නේ ලැයිස්තුවේ අහඹු මූලද්‍රව්‍ය හුවමාරුවක් භාවිතා කිරීමයි.

ව්‍යාජ කේත වලදී මෙය මෙසේ පෙනේ:

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

1
මෙම ප්‍රවේශයේ එක් ගැටළුවක් වන්නේ නැවැත්විය යුත්තේ කවදාද යන්න දැන ගැනීමයි. ව්‍යාජ සසම්භාවී සංඛ්‍යා උත්පාදක යන්ත්රයේ ඕනෑම නැඹුරුවක් අතිශයෝක්තියට නැංවීමේ ප්‍රවණතාවක් ද එයට ඇත.
මාර්ක් බෙසී

3
ඔව්. ඉහළ අකාර්යක්ෂමතාව. වඩා හොඳ, වේගවත් ප්‍රවේශයන් පවතින විට මෙවැනි ප්‍රවේශයක් භාවිතා කිරීමට කිසිදු හේතුවක් නැත.
පීටර්ඇලන් වෙබ්

1
ඉතා කාර්යක්ෂම හෝ effective ලදායී නොවේ ... එය N වාරයක් ධාවනය කිරීමෙන් බොහෝ මූලද්‍රව්‍ය ඒවායේ මුල් ස්ථානයට වැටෙනු ඇත.
NSjonas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.