C # හි සාමාන්ය ලැයිස්තුවක අනුපිළිවෙල අහඹු ලෙස කිරීමට හොඳම ක්රමය කුමක්ද? ලොතරැයි වර්ගයේ යෙදුමක් සඳහා ඒවා ඇද ගැනීම සඳහා අහඹු ඇණවුමක් ලබා දීමට මා කැමති ලැයිස්තුවක සීමිත අංක 75 ක කට්ටලයක් මා සතුව ඇත.
C # හි සාමාන්ය ලැයිස්තුවක අනුපිළිවෙල අහඹු ලෙස කිරීමට හොඳම ක්රමය කුමක්ද? ලොතරැයි වර්ගයේ යෙදුමක් සඳහා ඒවා ඇද ගැනීම සඳහා අහඹු ඇණවුමක් ලබා දීමට මා කැමති ලැයිස්තුවක සීමිත අංක 75 ක කට්ටලයක් මා සතුව ඇත.
Answers:
ෆිෂර්-යේට්ස් මාරුව(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;
}
}
}
}
Random rng = new Random();
කරයි static
. එක් එක් පසු ඇමතුම පෙර ඇමතුම් වලින් ලැබෙන බැවින් අවසාන අහඹු ප්රති .ලය.
අපට අවශ්ය වන්නේ අයිතම සම්පුර්ණයෙන්ම අහඹු පිළිවෙලකට මාරු කිරීමට නම් (ලැයිස්තුවේ ඇති අයිතම මිශ්ර කිරීමට පමණි), මම කැමති මෙම සරල නමුත් effective ලදායී කේතයට මග පෙන්වීමෙන් භාණ්ඩ ඇණවුම් කරන ...
var shuffledcards = cards.OrderBy(a => Guid.NewGuid()).ToList();
var shuffledcards = cards.OrderBy(a => rng.Next());
compilr.com/grenade/sandbox/Program.cs
NewGuid
එය ඔබට අද්විතීය GUID ලබා දෙන බවට සහතික කරයි. එය අහඹු බව පිළිබඳ සහතිකයක් ලබා නොදේ. අද්විතීය අගයක් නිර්මාණය කිරීම හැර වෙනත් අරමුණක් සඳහා ඔබ GUID භාවිතා කරන්නේ නම් , ඔබ එය වැරදිය.
මෙම සරල ඇල්ගොරිතමයේ සියලුම අපැහැදිලි අනුවාදයන් ගැන මම ටිකක් පුදුම වෙමි. ෆිෂර්-යේට්ස් (හෝ නුත් ෂෆල්) ටිකක් උපක්රමශීලී නමුත් ඉතා සංයුක්තයි. එය ව්යාකූල ඇයි? ඔබගේ අහඹු සංඛ්යා උත්පාදක යන්ත්රය ඇතුළත් කළ හෝ සුවිශේෂී වූ 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;
}
i = list.Count - 1
, එනම් අවසාන පුනරාවර්තනය rnd.Next(i, list.Count)
ඔබට නැවත ලබා දෙනු ඇත. එබැවින් ඔබට i < list.Count -1
ලූප් කොන්දේසිය ලෙස අවශ්ය වේ. හොඳයි, ඔබට එය 'අවශ්ය නැත', නමුත් එය 1 පුනරාවර්තනයක් ඉතිරි කරයි;)
0
හෝ list.Count-1
.
IEnumerable සඳහා දිගු කිරීමේ ක්රමය:
public static IEnumerable<T> Randomize<T>(this IEnumerable<T> source)
{
Random rnd = new Random();
return source.OrderBy<T, int>((item) => rnd.Next());
}
OrderBy
අයිතම ඒවායේ (පෙනෙන ලෙස අහඹු) යතුරු මගින් වර්ග කිරීමට ක්වික්සෝර්ට් ප්රභේදයක් භාවිතා කරයි. ක්වික්සෝර්ට් කාර්ය සාධනය ඕ (එන් ලොග් එන්) ; ඊට වෙනස්ව, ෆිෂර්-යේට්ස් මාරුව O (N) වේ. මූලද්රව්ය 75 ක එකතුවක් සඳහා, මෙය විශාල ගනුදෙනුවක් නොවිය හැකි නමුත් විශාල එකතු සඳහා වෙනස පැහැදිලි වනු ඇත.
Random.Next()
සාධාරණ ලෙස සසම්භාවී සාරධර්ම බෙදා හැරීමක් ඇති කළ හැකි නමුත් අගයන් අද්විතීය වනු ඇති බවට එය සහතික නොවේ . N 2 ^ 32 + 1 කරා ළඟා වන විට එය නිශ්චිතභාවයට පත්වන තෙක් N සමඟ අනුපිටපත් යතුරු වල සම්භාවිතාව (රේඛීය නොවන) වර්ධනය වේ. මෙම QuickSort යනු ස්ථාවර ආකාරයක; මේ අනුව, බහු මූලද්රව්ය එකම ව්යාජ සසම්භාවී දර්ශකය අගය පවරා ගැනීමට සිදු නම්, ප්රතිදානය අනුක්රමය ඔවුන්ගේ නියෝගය වනු ඇත එම යෙදවුම් අනුපිළිවෙල දී මෙන්, මේ අනුව, නැඹුරුවක් "මාරු කිරීම" තුළට හඳුන්වා දෙනු ලැබේ. OrderBy
අදහස යනු අයිතමය සහ අහඹු අනුපිළිවෙල සමඟ නිර්නාමික වස්තුවක් ලබාගෙන පසුව මෙම ඇණවුම සහ ප්රතිලාභ අගය අනුව අයිතම නැවත සකසන්න:
var result = items.Select(x => new { value = x, order = rnd.Next() })
.OrderBy(x => x.order).Select(x => x.value).ToList()
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;
}
var listCopy = list.ToList()
එන අයිතම ලැයිස්තුවෙන් ඉවත් නොකිරීමට ඔබ යමක් කළ යුතු නොවේද ? එම ලැයිස්තු හිස් කිරීමට විකෘති කිරීමට ඔබට අවශ්ය ඇයිදැයි මට නොපෙනේ.
සංස්කරණය
මෙම 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
නූල්-ආරක්ෂිත හෝ ගුප්ත විද්යාත්මකව ඔබේ අවශ්යතා සඳහා ප්රමාණවත් නොවේ නම්, ඔබට ක්රියාත්මක කිරීම ක්රියාත්මක කිරීමට එන්නත් කළ හැකිය.
මෙන්න අදහසක්, 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]];
}
GetNext
හෝ Next
?
මෙම සරල දිගු කිරීමේ ක්රමය භාවිතා කිරීමෙන් ඔබට එය සාක්ෂාත් කරගත හැකිය
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);
}
Random
පන්තියේ අවස්ථාව ශ්රිතයෙන් පිටත static
විචල්යයක් ලෙස තබමි. එසේ නොමැතිනම් ඉක්මන් අනුපිළිවෙලින් කැඳවනු ලැබුවහොත් ඔබට එම සසම්භාවීකරණ බීජය ටයිමරයෙන් ලබා ගත හැකිය.
මුල් පිටපත වෙනස් නොකිරීමට සුදුසු විට මෙය මගේ වඩාත් කැමති ක්රමයකි. එය ඕනෑම ගණන් කළ නොහැකි අනුක්රමයක් මත ක්රියා කරන ෆිෂර්-යේට්ස් “ඇතුළත-පිටත” ඇල්ගොරිතමයේ ප්රභේදයකි (දිග 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)];
විනෝද වන්න!
දෙකක් භාවිතා කිරීමට ඔබට අවශ්ය නැතිනම් 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);
ඔබට ස්ථාවර අංකයක් (75) තිබේ නම්, ඔබට මූලද්රව්ය 75 ක් සහිත අරාවක් සෑදිය හැකිය, ඉන්පසු ඔබේ ලැයිස්තුව ගණනය කරන්න, මූලද්රව්ය අරාවෙහි අහඹු ලෙස ස්ථාන කරා ගෙනයන්න. ෆිෂර්-යේට්ස් මාරුව භාවිතයෙන් ඔබට ලැයිස්තු අංක අරා දර්ශකයට සිතියම් ගත කළ හැකිය .
මම සාමාන්යයෙන් භාවිතා කරන්නේ:
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<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.
මාරු කළ අගයන් බයිට් පෙළක් ලබා දෙන කාර්යක්ෂම ෂෆ්ලර් මෙන්න. එය කිසි විටෙකත් අවශ්ය ප්රමාණයට වඩා වෙනස් නොවේ. එය කලින් අත්හැර දැමූ ස්ථානයෙන් නැවත ආරම්භ කළ හැකිය. මගේ සත්ය ක්රියාත්මක කිරීම (පෙන්වා නැත) යනු 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;
}
`
මෙය කිරීමට නූල් ආරක්ෂිත ක්රමයක් මෙන්න:
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());
}
}
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);
}
පිළිබඳ සරල වෙනස් පිළිගත් පිළිතුර වෙනුවට දී-ස්ථානය වැඩ නව ලැයිස්තුව නැවත, සහ වඩා පොදු පිළිගන්නා 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;
}
මම අන්තර්ජාලය හරහා රසවත් විසඳුමක් සොයාගෙන ඇත.
අනුග්රහය: https://improveandrepeat.com/2018/08/a-simple-way-to-shuffle-your-lists-in-c/
var shuffled = myList.OrderBy (x => Guid.NewGuid ()). ලැයිස්තු ගත කිරීම ();
නැවත පැමිණීමට අවශ්ය මූලද්රව්ය ගණන නියම කිරීමට ඉඩ සලසන ෆිෂර්-යේට්ස් මාරුව ක්රියාත්මක කිරීම මෙන්න; එබැවින්, ඔබ අපේක්ෂිත මූලද්රව්ය ගණන ගැනීමට පෙර මුලින්ම සම්පූර්ණ එකතුව වර්ග කිරීම අවශ්ය නොවේ.
හුවමාරු මූලද්රව්යවල අනුක්රමය පෙරනිමියෙන් ආපසු හරවනු ලැබේ; පළමු මූලද්රව්යයේ සිට අවසාන මූලද්රව්යය දක්වා ඉදිරියට යන අතර එමඟින් එකතුවේ උප කුලකයක් ලබා ගැනීමෙන් සමස්ත එකතුවම මාරු කිරීමේ සමාන (අර්ධ) අනුක්රමය ලැබේ:
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;
}
ඔබේ ප්රශ්නය වන්නේ ලැයිස්තුවක් අහඹු ලෙස සකසන්නේ කෙසේද යන්නයි . මෙයින් අදහස් වන්නේ:
මෙම ප්රශ්නය සඳහා පළ කර ඇති පිළිතුරු විශාල සංඛ්යාවක් “අහඹු” වීම සඳහා ඉහත අවශ්යතා දෙක සපුරාලන්නේ නැත.
ෆිෂර්-යේට්ස් මාරු කිරීමේ ක්රමය අනුගමනය කරන සංයුක්ත, පක්ෂග්රාහී නොවන ව්යාජ අහඹු ශ්රිතයක් මෙන්න.
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;
}
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());
පැරණි පෝස්ට් නිසැකවම, නමුත් මම භාවිතා කරන්නේ GUID ය.
Items = Items.OrderBy(o => Guid.NewGuid().ToString()).ToList();
GUID සෑම විටම අද්විතීය වන අතර, එය ප්රතිනිර්මාණය වන සෑම අවස්ථාවකම ප්රති result ලය වෙනස් වේ.
මේ ආකාරයේ ගැටළුවකට ඉතා සරල ප්රවේශයක් වන්නේ ලැයිස්තුවේ අහඹු මූලද්රව්ය හුවමාරුවක් භාවිතා කිරීමයි.
ව්යාජ කේත වලදී මෙය මෙසේ පෙනේ:
do
r1 = randomPositionInList()
r2 = randomPositionInList()
swap elements at index r1 and index r2
for a certain number of times