সি # তে <T> একটি তালিকা থেকে এন এলোমেলো উপাদান নির্বাচন করুন


158

জেনেরিক তালিকা থেকে ৫ টি এলোমেলো উপাদান নির্বাচন করার জন্য আমার দ্রুত অ্যালগরিদম প্রয়োজন। উদাহরণস্বরূপ, আমি এ থেকে 5 টি এলোমেলো উপাদান পেতে চাই List<string>


11
এলোমেলোভাবে, আপনার অর্থ কী অন্তর্ভুক্ত বা এক্সক্লুসিভ? IOW, একই উপাদানটি একাধিকবার বাছাই করা যাবে? (সত্যই এলোমেলো) অথবা একবার কোনও উপাদান বাছাই করা গেলে, এটি কি আর উপলব্ধ পুল থেকে বেছে নেওয়া উচিত নয়?
প্রিটজেল

উত্তর:


127

প্রতিটি উপাদানের মাধ্যমে এবং এর জন্য আইট্রেট করুন নির্বাচনের সম্ভাব্যতাটি তৈরি করুন = (প্রয়োজনীয় নম্বর) / (নম্বরটি বাম)

সুতরাং আপনার যদি 40 টি আইটেম থাকে তবে প্রথমটির কাছে নির্বাচিত হওয়ার 5/40 সুযোগ থাকবে। যদি এটি হয় তবে পরেরটির কাছে 4/39 টির সুযোগ রয়েছে, অন্যথায় এটিতে 5/39 এর সুযোগ রয়েছে। আপনি শেষে পৌঁছানোর সময় আপনার কাছে আপনার 5 টি আইটেম থাকবে এবং প্রায়শই আপনার আগে সেগুলি হয়ে যাবে।


33
আমি মনে করি এটি সূক্ষ্মভাবে ভুল। মনে হচ্ছে তালিকার পিছনের দিকটি সামনের প্রান্তের চেয়ে প্রায়শই বাছাই করা হবে কারণ পিছনের প্রান্তটি আরও বড় সম্ভাবনা দেখতে পাবে। উদাহরণস্বরূপ, যদি প্রথম 35 নম্বরটি বাছাই না করা হয় তবে সর্বশেষ 5 নম্বর বাছাই করতে হবে। প্রথম সংখ্যাটি কেবল 5/40 টির মতো সুযোগ দেখতে পাবে, তবে সেই শেষ সংখ্যাটি 1/1 বার 5/40 বারের চেয়ে বেশি বার দেখতে পাবে। এই অ্যালগরিদমটি প্রয়োগ করার আগে আপনাকে প্রথমে তালিকাটি এলোমেলো করতে হবে।
অঙ্কুর গোয়েল

23
ঠিক আছে, আমি 40 টি এলিমেন্টের তালিকায় এই অ্যালগরিদমটি 10 ​​মিলিয়ন বার দৌড়েছি, প্রতিটি নির্বাচিত হওয়ার সময় 5/40 (.125) শট নিয়ে এবং পরে সেই সিমুলেশনটি বেশ কয়েকবার চালিয়েছি। দেখা যাচ্ছে যে এটি সমানভাবে বিতরণ করা হয়নি। উপাদানসমূহ 16 থেকে 22 এর মধ্যে নিম্নচিকিত্সা পান (16 = .123, 17 = .124), যখন উপাদান 34 পর্যবেক্ষণ করা হবে (34 = .129)। 39 এবং 40 এর উপাদানগুলিও নীচে নির্বাচিত হয়ে যায় তবে তত বেশি নয় (39 = .1247, 40 = .1246)
অঙ্কুর গোয়েল

21
@ অঙ্কুর: আমি বিশ্বাস করি না যে এটি পরিসংখ্যানগতভাবে তাৎপর্যপূর্ণ। আমি বিশ্বাস করি যে এটি একটি এমনকি বিতরণ প্রদান করবে একটি প্ররোচক প্রমাণ আছে।
পুনরাবৃত্তি

9
আমি একই পরীক্ষাকে 100 মিলিয়ন বার পুনরাবৃত্তি করেছি এবং আমার পরীক্ষায় সর্বাধিক নির্বাচিত আইটেমটির চেয়ে কমপক্ষে নির্বাচিত আইটেমটি 0.106% এর চেয়ে কম বার নির্বাচিত হয়েছিল।
পুনরাবৃত্তি

5
@ রিসার্সিভ: প্রমাণটি প্রায় তুচ্ছ। আমরা জানি যে কোনও কে-এর জন্য কে থেকে আই-কে কীভাবে নির্বাচন করতে হয় এবং এন-এর বাইরে 0 টি আইটেম কীভাবে নির্বাচন করতে হয়। অনুমান আমরা N-1> = K এর বাইরে কে বা কে -1 আইটেম নির্বাচন করতে একটি পদ্ধতি জানি; তারপরে আমরা সম্ভাব্যতা কে / এন সহ প্রথম আইটেমটি নির্বাচন করে এবং তারপরে অবশিষ্ট এন -1 এর বাইরে প্রয়োজনীয় কে বা কে -1 আইটেম নির্বাচন করার জন্য জ্ঞাত পদ্ধতিটি ব্যবহার করে আমরা এন এর বাইরে কে আইটেম নির্বাচন করতে পারি।
ইলমারি করোনেন

216

লিনাক ব্যবহার:

YourList.OrderBy(x => rnd.Next()).Take(5)

2
+1 তবে যদি দুটি উপাদান rnd.Next () বা অনুরূপ থেকে একই সংখ্যা পায় তবে প্রথমটি নির্বাচিত হবে এবং দ্বিতীয়টি সম্ভবত না হবে (যদি আরও উপাদানগুলির প্রয়োজন না হয়)। যদিও এটি ব্যবহারের উপর নির্ভর করে যথাযথভাবে এলোমেলো।
ল্যাসে এসপোল্ট

7
আমি মনে করি এর দ্বারা আদেশটি হ'ল (এন লগ (এন)), সুতরাং কোড সরলতা যদি প্রধান উদ্বেগ হয় (তবে ছোট তালিকা সহ) তবে আমি এই সমাধানটি বেছে নেব।
গাইডো

2
তবে এটি পুরো তালিকাটি গণনা করে বাছাই করে না? "দ্রুত" দ্বারা, ওপি মানে "সহজ", "পারফর্মেন্ট" নয় ...
ড্রজাউস

2
এটি কেবল তখনই কাজ করবে যদি অর্ডারবাই () প্রতিটি উপাদানগুলির জন্য কেবলমাত্র নির্বাচককে কল করে। এটি যখনই এটি কল করে যখনই এটি দুটি উপাদানের মধ্যে তুলনা সম্পাদন করতে চায় তবে প্রতিবার এটি পৃথক পৃথক মান পাবে, যা সাজানোর জন্য স্ক্রু তৈরি করবে। [ডকুমেন্টেশন] ( এমএসডিএন.মাইক্রোসফটকম / en-us / library / vstudio/… ) এটি যা করে তা বলে না।
অলিভার বক

2
YourListপ্রচুর আইটেম রয়েছে কিনা তা দেখুন তবে আপনি কেবল কয়েকটি নির্বাচন করতে চান। এই ক্ষেত্রে এটি করার একটি দক্ষ উপায় নয়।
কলম ওয়াটকিন্স

39
public static List<T> GetRandomElements<T>(this IEnumerable<T> list, int elementsCount)
{
    return list.OrderBy(arg => Guid.NewGuid()).Take(elementsCount).ToList();
}

27

এটি যেমন মনে হয় ততই এটি একটি শক্ত সমস্যা, মূলত কারণ অনেকগুলি গাণিতিকভাবে সঠিক সমাধানগুলি আপনাকে সমস্ত সম্ভাবনাগুলিতে আঘাত করতে দেয় না (এটি নীচে আরও)।

প্রথমত, বাস্তবায়িত কিছু সহজ, সঠিক-যদি-আপনার-সত্য-র্যান্ডম-সংখ্যার জেনারেটর থাকে তবে:

(0) কাইলের উত্তর, যা ও (এন)।

(1) এন জোড়ার একটি তালিকা তৈরি করুন [(0, র্যান্ড), (1, র্যান্ড), (2, র্যান্ড), ...], তাদের দ্বিতীয় স্থানাঙ্ক অনুসারে বাছাই করুন এবং প্রথম কে ব্যবহার করুন (আপনার জন্য, কে = 5) সূচকগুলি আপনার এলোমেলো উপসেট পেতে। আমি মনে করি এটি কার্যকর করা সহজ, যদিও এটি ও (এন লগ এন) সময়।

(২) একটি খালি তালিকা শুরু করুন s = [] যা কে এলোমেলো উপাদানগুলির সূচক হিসাবে বাড়বে। Rand 0, 1, 2, ..., n-1 in এলোমেলোভাবে, r = র্যান্ড% n এ একটি নম্বর আর চয়ন করুন এবং এটিতে যোগ করুন। এরপরে আর = র‌্যান্ড% (n-1) নিন এবং এর মধ্যে থাকুন; সংঘর্ষ এড়াতে # টি উপাদানের চেয়ে কম উপাদান যুক্ত করুন। এরপরে আর = র‌্যান্ড% (এন -২) নিন এবং আপনার এস এর মধ্যে স্বতন্ত্র উপাদান না পাওয়া পর্যন্ত একই জিনিস ইত্যাদি করুন। এটি চলমান সময় হে (কে ^ 2) এর সবচেয়ে খারাপ ক্ষেত্রে রয়েছে। সুতরাং কে << এন এর জন্য এটি দ্রুত হতে পারে। যদি আপনি এইভাবে বাছাই করে রাখেন এবং এর সাথে কোন স্বতন্ত্র অন্তরগুলি ট্র্যাক করে থাকেন তবে আপনি এটিকে ও (কে লগ কে) এ প্রয়োগ করতে পারেন, তবে এটি আরও কাজ।

@ কাইল - ঠিক বলেছেন, দ্বিতীয় ভাবাতে আমি আপনার উত্তরের সাথে একমত হই। আমি তাড়াতাড়ি এটি প্রথমে পড়েছি এবং ভুল করে ভেবেছি আপনি স্থির সম্ভাব্য কে / এন দিয়ে প্রতিটি উপাদান যথাযথভাবে বেছে নেওয়ার ইঙ্গিত দিচ্ছেন, যা ভুল হত - তবে আপনার অভিযোজিত পদ্ধতিটি আমার কাছে সঠিক বলে মনে হচ্ছে। এর জন্যে দুঃখিত.

ঠিক আছে, এবং এখন কিকারের জন্য: asympototically (স্থির কে, এন বর্ধনের জন্য), সেখানে এন ^ কে / কে আছে! কে উপাদানগুলির পছন্দগুলি এন উপাদানগুলির মধ্যে উপসেট হয় [এটি একটি (এন নির্বাচন কে) এর একটি অনুমান)। যদি এন বড় হয় এবং কে খুব ছোট না হয় তবে এই সংখ্যাগুলি বিশাল। যে কোনও স্ট্যান্ডার্ড 32 বিট এলোমেলো সংখ্যা জেনারেটরের জন্য আপনি আশা করতে পারেন সর্বোত্তম চক্রের দৈর্ঘ্য হ'ল 2 ^ 32 = 256 ^ 4। সুতরাং যদি আমাদের কাছে 1000 উপাদানগুলির একটি তালিকা থাকে এবং আমরা এলোমেলোভাবে 5 টি চয়ন করতে চাই, তবে কোনও স্ট্যান্ডার্ড এলোমেলো সংখ্যা জেনারেটর সমস্ত সম্ভাবনা হিট করার উপায় নেই। তবে যতক্ষণ না আপনি ছোট্ট সেটগুলির জন্য সূক্ষ্মভাবে কাজ করে এমন কোনও পছন্দ দিয়ে ঠিক থাকেন এবং সর্বদা এলোমেলোভাবে "দেখায়" ততক্ষণ এই অ্যালগোরিদমগুলি ঠিক থাকা উচিত।

সংযোজন : এটি লেখার পরে, আমি বুঝতে পেরেছিলাম যে ধারণা (2) সঠিকভাবে প্রয়োগ করা কঠিন, সুতরাং আমি এই উত্তরটি পরিষ্কার করতে চেয়েছিলাম। ও (কে লগ কে) সময় পেতে আপনার একটি অ্যারের মতো কাঠামো দরকার যা ও (লগ এম) অনুসন্ধান এবং সন্নিবেশগুলিকে সমর্থন করে - একটি ভারসাম্য বাইনারি গাছ এটি করতে পারে। এস নামক একটি অ্যারে তৈরি করতে এ জাতীয় কাঠামো ব্যবহার করে এখানে কিছু সিউডোপथिথন দেওয়া হয়েছে:

# Returns a container s with k distinct random numbers from {0, 1, ..., n-1}
def ChooseRandomSubset(n, k):
  for i in range(k):
    r = UniformRandom(0, n-i)                 # May be 0, must be < n-i
    q = s.FirstIndexSuchThat( s[q] - q > r )  # This is the search.
    s.InsertInOrder(q ? r + q : r + len(s))   # Inserts right before q.
  return s

আমি উপরের ইংরাজী ব্যাখ্যাটি কীভাবে দক্ষতার সাথে প্রয়োগ করে তা দেখতে কয়েকটি নমুনা কেস চালানোর পরামর্শ দিই।


2
(1) আপনি বাছাই করার চেয়ে দ্রুত তালিকার সাথে তাল মিলিয়ে নিতে পারেন, (২) আপনি%
jk

আপনি কোনও আরএনজি চক্রের দৈর্ঘ্য সম্পর্কে উত্থাপিত আপত্তিটি দিয়েছিলেন, এমন কোনও উপায় কি আমরা একটি অ্যালগরিদম তৈরি করতে পারি যা সমান সম্ভাবনার সাথে সমস্ত সেট বেছে নেবে?
জোনা

(1) এর জন্য, ও (এন লগ (এন)) উন্নত করতে আপনি কে সর্বাধিক উপাদান খুঁজে বের করতে বাছাই বাছাই করতে পারেন। ও (এন * কে) এ চলবে।
জেরেড

@ জোনাঃ আমারও তাই মনে হয়। ধরে নেওয়া যাক আমরা একটি বৃহত্তর একটি তৈরি করতে একাধিক স্বতন্ত্র এলোমেলো সংখ্যা জেনারেটর একত্রিত করতে পারি ( crypto.stackexchange.com/a/27431 )। তারপরে আপনার প্রশ্নের মধ্যে থাকা আকারের আকারটি মোকাবেলা করার জন্য কেবল একটি বৃহত পর্যাপ্ত পরিসর দরকার।
জেরেড

16

আমি মনে করি নির্বাচিত উত্তরটি সঠিক এবং বেশ মিষ্টি। আমি যদিও এটি এলোমেলোভাবে ক্রম ফলাফল চেয়েছিলেন হিসাবে এটি অন্যভাবে বাস্তবায়িত।

    static IEnumerable<SomeType> PickSomeInRandomOrder<SomeType>(
        IEnumerable<SomeType> someTypes,
        int maxCount)
    {
        Random random = new Random(DateTime.Now.Millisecond);

        Dictionary<double, SomeType> randomSortTable = new Dictionary<double,SomeType>();

        foreach(SomeType someType in someTypes)
            randomSortTable[random.NextDouble()] = someType;

        return randomSortTable.OrderBy(KVP => KVP.Key).Take(maxCount).Select(KVP => KVP.Value);
    }

অসাধারণ! সত্যিই আমাকে সাহায্য করেছে!
আর্মস্ট্রোনস্ট

1
নতুন র্যান্ডম () যা পরিবেশ.টিককাউন্ট বনাম ডেটটাইম.নিউ.মিলিসেকেন্ডের উপর ভিত্তি করে ব্যবহার না করার কোনও কারণ আছে?
ল্যাসে এসপোল্ট

না, ঠিক জানা ছিল না যে ডিফল্টটির অস্তিত্ব রয়েছে।
ফ্র্যাঙ্ক শোয়েটারম্যান

র্যান্ডমসোর্টটিবলের একটি ইনগ্রোভমেন্ট: র্যান্ডমসোর্টটিবল = কিছু টাইপস T ফোরচ লুপ সংরক্ষণ করে।
কেলটেক্স

2
ঠিক এক বছর দেরীতে কিন্তু ... এই বার্তাটি কি এরসিনের পরিবর্তে সংক্ষিপ্ত উত্তরটি খুঁজে বের করে না এবং আপনি যদি বারবার এলোমেলো নম্বর পেয়ে থাকেন তবে তা ব্যর্থ হবে না (যেখানে এরসিনের পুনরাবৃত্তি জোড়ার প্রথম আইটেমটির প্রতি পক্ষপাতিত্ব থাকবে)
Andiih

12

আমি কেবল এই সমস্যায় পড়েছি এবং আরও কিছু গুগল অনুসন্ধান আমাকে এলোমেলোভাবে একটি তালিকা বদলানোর সমস্যাটিতে নিয়ে এসেছিল: http://en.wikedia.org/wiki/Fisher- Yates_shuffle

সম্পূর্ণরূপে এলোমেলোভাবে আপনার তালিকাটি স্থান পরিবর্তন করতে (জায়গায়) আপনি এটি করুন:

একটি এন অ্যারের একটি অ্যারে পরিবর্তন করতে (সূচক 0..n-1):

  for i from n  1 downto 1 do
       j  random integer with 0  j  i
       exchange a[j] and a[i]

আপনার যদি কেবল প্রথম 5 টি উপাদান প্রয়োজন হয় তবে n-1 থেকে 1 পর্যন্ত সমস্ত পথ চালানোর পরিবর্তে আপনার কেবল এটি এন -5 চালানো উচিত (যেমন: এন -5)

বলুন আপনাকে কে আইটেমের প্রয়োজন হবে,

এটি হয়ে:

  for (i = n  1; i >= n-k; i--)
  {
       j = random integer with 0  j  i
       exchange a[j] and a[i]
  }

নির্বাচিত প্রতিটি আইটেমটি অ্যারের শেষের দিকে অদলবদল করা হয়, সুতরাং নির্বাচিত কে উপাদানগুলি অ্যারের শেষ কে উপাদানগুলি।

এটি সময় নেবে O (কে), যেখানে k আপনার প্রয়োজনীয় এলোমেলোভাবে নির্বাচিত উপাদানগুলির সংখ্যা।

এছাড়াও, আপনি যদি আপনার প্রাথমিক তালিকাকে সংশোধন করতে না চান, আপনি নিজের সমস্ত অদল বদল অস্থায়ী তালিকায় লিখতে পারেন, সেই তালিকাটি আবার বিপরীত করতে পারেন এবং সেগুলি আবার প্রয়োগ করতে পারেন, এভাবে অদলবদলের বিপরীত সেট সম্পাদন করে এবং পরিবর্তন না করেই আপনাকে আপনার প্রাথমিক তালিকা ফিরিয়ে দিতে পারেন ও (কে) চলমান সময়।

অবশেষে, আসল স্টিকারারের জন্য, যদি (n == কে) হয় তবে আপনার এনকে নয়, 1 এ থামানো উচিত, কারণ এলোমেলোভাবে নির্বাচিত পূর্ণসংখ্যা সর্বদা 0 হবে।


আমি এটি আমার ব্লগ পোস্টে সি # ব্যবহার করে প্রয়োগ করেছি: vijayt.com/post/random-select-using-fisher-yates-algorithm । আশা করি এটি কাউকে # # উপায় অনুসন্ধানে সহায়তা করবে।
বিজয়স্ট

9

আপনি এটি ব্যবহার করতে পারেন তবে ক্রম ক্লায়েন্টের পক্ষেই ঘটবে

 .AsEnumerable().OrderBy(n => Guid.NewGuid()).Take(5);

একমত। এটি সেরা পারফর্মিং বা সর্বাধিক এলোমেলো নাও হতে পারে, তবে বিপুল সংখ্যক লোকের পক্ষে এটি যথেষ্ট ভাল।
রিচিবান


8

অ্যালগরিদমে ড্রাগন থেকে , সি # তে একটি ব্যাখ্যা:

int k = 10; // items to select
var items = new List<int>(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 });
var selected = new List<int>();
double needed = k;
double available = items.Count;
var rand = new Random();
while (selected.Count < k) {
   if( rand.NextDouble() < needed / available ) {
      selected.Add(items[(int)available-1])
      needed--;
   }
   available--;
}

এই অ্যালগরিদম আইটেম তালিকার অনন্য সূচি নির্বাচন করবে।


কেবলমাত্র তালিকায় পর্যাপ্ত আইটেম পান তবে এলোমেলোভাবে পান না।
পুলিথেয়

2
এই প্রয়োগটি ভেঙে গেছে কারণ varফলাফলগুলি ব্যবহার করে neededএবং availableউভয়ই পূর্ণসংখ্যা হয় যা needed/availableসর্বদা 0 হয়
নিকো

1
এটি গৃহীত উত্তরের একটি বাস্তবায়ন বলে মনে হচ্ছে।
ডিসিএসনন

6

একটি গ্রুপ থেকে এন এলোমেলো আইটেম নির্বাচন করার সাথে অর্ডার করার কিছু নেই ! এলোমেলোতা অদম্যতা সম্পর্কে এবং কোনও গ্রুপে অবস্থান বদলের বিষয়ে নয়। কিছু জবাব যা কিছু কিন্ডার অর্ডার নিয়ে কাজ করে সেগুলির তুলনায় কম দক্ষ হতে বাধ্য। দক্ষতা এখানে মূল কারণ, আমি এমন কিছু পোস্ট করব যা আইটেমগুলির ক্রমকে খুব বেশি পরিবর্তন করে না।

1) আপনার যদি সত্যিকারের এলোমেলো মানগুলির প্রয়োজন হয় যার অর্থ কোন উপাদানগুলির মধ্যে থেকে কোনটি বেছে নেওয়ার উপর কোনও বিধিনিষেধ নেই (যেমন, একবার নির্বাচিত আইটেমটি পুনরায় প্রকাশ করা যেতে পারে):

public static List<T> GetTrueRandom<T>(this IList<T> source, int count, 
                                       bool throwArgumentOutOfRangeException = true)
{
    if (throwArgumentOutOfRangeException && count > source.Count)
        throw new ArgumentOutOfRangeException();

    var randoms = new List<T>(count);
    randoms.AddRandomly(source, count);
    return randoms;
}

আপনি যদি ব্যতিক্রম পতাকাটি অফ করে রাখেন, তবে আপনি যেকোন সংখ্যক বার এলোমেলো আইটেম চয়ন করতে পারেন।

আপনার যদি {1, 2, 3, 4 {থাকে, তবে এটি 3 আইটেমের জন্য এমনকি 1 ডলার, 4, 3, 2, 4} দিতে পারে, 1, 4, 4 4, {1, 4, 3} ইত্যাদি 5 টি আইটেম!

এটি বেশ দ্রুত হওয়া উচিত, কারণ এটির যাচাই করার মতো কিছুই নেই।

২) যদি কোনও পুনরাবৃত্তি না করে গোষ্ঠী থেকে পৃথক সদস্যের আপনার প্রয়োজন হয় , তবে আমি একটি অভিধানের উপর নির্ভর করব (যেমন অনেকে ইতিমধ্যে নির্দেশ করেছেন)।

public static List<T> GetDistinctRandom<T>(this IList<T> source, int count)
{
    if (count > source.Count)
        throw new ArgumentOutOfRangeException();

    if (count == source.Count)
        return new List<T>(source);

    var sourceDict = source.ToIndexedDictionary();

    if (count > source.Count / 2)
    {
        while (sourceDict.Count > count)
            sourceDict.Remove(source.GetRandomIndex());

        return sourceDict.Select(kvp => kvp.Value).ToList();
    }

    var randomDict = new Dictionary<int, T>(count);
    while (randomDict.Count < count)
    {
        int key = source.GetRandomIndex();
        if (!randomDict.ContainsKey(key))
            randomDict.Add(key, sourceDict[key]);
    }

    return randomDict.Select(kvp => kvp.Value).ToList();
}

কোডটি এখানে অন্যান্য অভিধানের পদ্ধতির চেয়ে কিছুটা দীর্ঘতর কারণ আমি কেবল যুক্ত করছি না, তবে তালিকা থেকেও সরিয়ে দিচ্ছি, সুতরাং এর কিন্ডার দুটি লুপ রয়েছে। আপনি এখানে দেখতে পারেন যে, আমি নি পুনর্বিন্যস্তভাবে সব কিছু যখন countসমান হয়ে source.Count। এটা এ কারণে যে আমি বিশ্বাস করি যদৃচ্ছতা মধ্যে থাকা উচিত ফিরে সেট সামগ্রিকভাবে । আমি বলতে চাচ্ছি তুমি যদি চাও 5 র্যান্ডম আইটেম থেকে 1, 2, 3, 4, 5, এটা ব্যাপার যদি তার করা উচিত নয় 1, 3, 4, 2, 5বা 1, 2, 3, 4, 5, কিন্তু যদি আপনি প্রয়োজন 4 একই সেট থেকে আইটেমগুলি, তাহলে এটি বিনা পূর্বাভাসেই মধ্যে উত্পাদ উচিত 1, 2, 3, 4, 1, 3, 5, 2, 2, 3, 5, 4ইত্যাদি দ্বিতীয়ত, যখন র্যান্ডম আইটেম গণনা করা প্রত্যাবর্তনটি মূল গোষ্ঠীর অর্ধেকেরও বেশি, তারপরে এটি সরানো সহজsource.Count - countআইটেম যোগ করার চেয়ে গ্রুপ থেকেcount আইটেম। পারফরম্যান্সের কারণে আমি অপসারণ পদ্ধতিতে র্যান্ডম সূচক পাওয়ার sourceপরিবর্তে ব্যবহার করেছি sourceDict

সুতরাং আপনার যদি {1, 2, 3, 4। থাকে তবে এটি 3 টি আইটেমের জন্য {1, 2, 3}, {3, 4, 1} ইত্যাদিতে শেষ হতে পারে।

3) যদি আপনার মূল গোষ্ঠীর নকলগুলি আমলে নিয়ে আপনার গোষ্ঠী থেকে সত্যই স্বতন্ত্র এলোমেলো মান প্রয়োজন হয় তবে আপনি উপরের মত একই পদ্ধতি ব্যবহার করতে পারেন, তবে HashSetএকটি অভিধানের চেয়ে হালকা হবে।

public static List<T> GetTrueDistinctRandom<T>(this IList<T> source, int count, 
                                               bool throwArgumentOutOfRangeException = true)
{
    if (count > source.Count)
        throw new ArgumentOutOfRangeException();

    var set = new HashSet<T>(source);

    if (throwArgumentOutOfRangeException && count > set.Count)
        throw new ArgumentOutOfRangeException();

    List<T> list = hash.ToList();

    if (count >= set.Count)
        return list;

    if (count > set.Count / 2)
    {
        while (set.Count > count)
            set.Remove(list.GetRandom());

        return set.ToList();
    }

    var randoms = new HashSet<T>();
    randoms.AddRandomly(list, count);
    return randoms.ToList();
}

randomsপরিবর্তনশীল একটি তৈরি করা হয় HashSetএড়াতে সদৃশ বিরল ঘটনা ক্ষেত্রে যেখানে এর বিরল ঘটনা মধ্যে যোগ করা হচ্ছে Random.Nextএকই মান উত্পাদ করতে পারেন, বিশেষত যখন ইনপুট তালিকা ছোট।

সুতরাং {1, 2, 2, 4} => 3 এলোমেলো আইটেম => {1, 2, 4} এবং কখনই {1, 2, 2}

{1, 2, 2, 4} => 4 এলোমেলো আইটেম => ব্যতিক্রম !! অথবা পতাকা সেটের উপর নির্ভর করে {1, 2, 4।।

কিছু এক্সটেনশন পদ্ধতি আমি ব্যবহার করেছি:

static Random rnd = new Random();
public static int GetRandomIndex<T>(this ICollection<T> source)
{
    return rnd.Next(source.Count);
}

public static T GetRandom<T>(this IList<T> source)
{
    return source[source.GetRandomIndex()];
}

static void AddRandomly<T>(this ICollection<T> toCol, IList<T> fromList, int count)
{
    while (toCol.Count < count)
        toCol.Add(fromList.GetRandom());
}

public static Dictionary<int, T> ToIndexedDictionary<T>(this IEnumerable<T> lst)
{
    return lst.ToIndexedDictionary(t => t);
}

public static Dictionary<int, T> ToIndexedDictionary<S, T>(this IEnumerable<S> lst, 
                                                           Func<S, T> valueSelector)
{
    int index = -1;
    return lst.ToDictionary(t => ++index, valueSelector);
}

যদি তালিকার দশটি আইটেমের দশ সহস্র গুণমান সম্পন্ন 10000 বার পুনরুক্তি করা উচিত, তবে আপনার তুলনায় দ্রুত এলোমেলো ক্লাস থাকতে পারে System.Randomতবে আমি সম্ভবত মনে করি না যে এটি সম্ভবত সবচেয়ে বড় বিষয় কখনও নয় বাধা, এটি যথেষ্ট দ্রুত ..

সম্পাদনা করুন: আপনার যদি ফেরত আইটেমগুলির ক্রমও আবার সাজানোর দরকার হয়, তবে hakাকিমের ফিশার-ইয়েটসের পদ্ধতিকে হারাতে পারে এমন কিছুই নেই - সংক্ষিপ্ত, মিষ্টি এবং সহজ ..


6

(প্যারাফ্রেজ) সম্পর্কিত গৃহীত উত্তরে @ জনশেডলেটস্কির মন্তব্য সম্পর্কে ভাবছিলেন :

আপনি ও (উপসেট.লেন্থ) এর চেয়ে ও (অরিজিনাল লিস্ট। দৈর্ঘ্য) এর পরিবর্তে সক্ষম হবেন

মূলত, আপনার উত্পন্ন করতে সক্ষম হওয়া উচিত subset এলোমেলো সূচকগুলি এবং তারপরে এগুলি মূল তালিকা থেকে ছিনিয়ে নেওয়া উচিত।

পদ্ধতি

public static class EnumerableExtensions {

    public static Random randomizer = new Random(); // you'd ideally be able to replace this with whatever makes you comfortable

    public static IEnumerable<T> GetRandom<T>(this IEnumerable<T> list, int numItems) {
        return (list as T[] ?? list.ToArray()).GetRandom(numItems);

        // because ReSharper whined about duplicate enumeration...
        /*
        items.Add(list.ElementAt(randomizer.Next(list.Count()))) ) numItems--;
        */
    }

    // just because the parentheses were getting confusing
    public static IEnumerable<T> GetRandom<T>(this T[] list, int numItems) {
        var items = new HashSet<T>(); // don't want to add the same item twice; otherwise use a list
        while (numItems > 0 )
            // if we successfully added it, move on
            if( items.Add(list[randomizer.Next(list.Length)]) ) numItems--;

        return items;
    }

    // and because it's really fun; note -- you may get repetition
    public static IEnumerable<T> PluckRandomly<T>(this IEnumerable<T> list) {
        while( true )
            yield return list.ElementAt(randomizer.Next(list.Count()));
    }

}

আপনি যদি আরও বেশি দক্ষ হতে চেয়েছিলেন, তাহলে আপনি সম্ভবত একটি ব্যবহার করেন HashSetএর সূচকের , প্রকৃত তালিকা উপাদানের (যদি আপনি জটিল ধরনের বা ব্যয়বহুল তুলনা পেয়েছেন);

ইউনিট পরীক্ষা

এবং আমাদের কোনও সংঘর্ষ নেই ইত্যাদি নিশ্চিত করার জন্য

[TestClass]
public class RandomizingTests : UnitTestBase {
    [TestMethod]
    public void GetRandomFromList() {
        this.testGetRandomFromList((list, num) => list.GetRandom(num));
    }

    [TestMethod]
    public void PluckRandomly() {
        this.testGetRandomFromList((list, num) => list.PluckRandomly().Take(num), requireDistinct:false);
    }

    private void testGetRandomFromList(Func<IEnumerable<int>, int, IEnumerable<int>> methodToGetRandomItems, int numToTake = 10, int repetitions = 100000, bool requireDistinct = true) {
        var items = Enumerable.Range(0, 100);
        IEnumerable<int> randomItems = null;

        while( repetitions-- > 0 ) {
            randomItems = methodToGetRandomItems(items, numToTake);
            Assert.AreEqual(numToTake, randomItems.Count(),
                            "Did not get expected number of items {0}; failed at {1} repetition--", numToTake, repetitions);
            if(requireDistinct) Assert.AreEqual(numToTake, randomItems.Distinct().Count(),
                            "Collisions (non-unique values) found, failed at {0} repetition--", repetitions);
            Assert.IsTrue(randomItems.All(o => items.Contains(o)),
                        "Some unknown values found; failed at {0} repetition--", repetitions);
        }
    }
}

2
সমস্যা নিয়ে দুর্দান্ত ধারণা। (1) যদি আপনার বৃহত তালিকাটি বিশাল হয় (উদাহরণস্বরূপ একটি ডাটাবেস থেকে পড়ুন) তবে আপনি পুরো তালিকাটি উপলব্ধি করতে পারেন যা স্মৃতি ছাড়িয়ে যেতে পারে। (২) কে যদি এন এর কাছাকাছি থাকে, তবে আপনি আপনার লুপে দাবি ছাড়াই সূচকের জন্য অনেকগুলি অনুসন্ধান করতে পারেন, যার ফলে কোডটির একটি অবিশ্বাস্য সময়ের প্রয়োজন হয়। এই সমস্যাগুলি সমাধানযোগ্য।
পল চেরনোচ

1
ছত্রভঙ্গ হওয়ার সমস্যাটির জন্য আমার সমাধানটি হ'ল: যদি কে <এন / 2, এটি আপনার উপায়ে করুন। যদি কে> = এন / ২, তবে যে সূচকগুলি রাখা উচিত নয়, তার পরিবর্তে যেগুলি রাখা উচিত choose এখনও কিছু ছোঁড়াছুড়ি রয়েছে, তবে অনেক কম।
পল চেরনোচ

এছাড়াও লক্ষ্য করা গেছে যে এটি গণনা করা আইটেমগুলির ক্রমকে পরিবর্তিত করে যা কিছু পরিস্থিতিতে গ্রহণযোগ্য হতে পারে তবে অন্যের ক্ষেত্রে তা নয়।
পল চেরনোচ

গড়ে, কে = এন / 2 (পলের প্রস্তাবিত উন্নতির জন্য সবচেয়ে খারাপ ক্ষেত্রে) এর জন্য, (থ্র্যাশিং উন্নত) অ্যালগরিদমটি ~ 0.693 * এন পুনরুক্তি করে বলে মনে হয়। এখন একটি গতি তুলনা করুন। এটি কি গৃহীত উত্তরের চেয়ে ভাল? কোন নমুনা আকারের জন্য?
mbomb007

6

আমি একটি লাজিলি-মূল্যায়িত এক্সটেনশন পদ্ধতি তৈরি করতে উপরের বেশ কয়েকটি উত্তর একত্রিত করেছি। আমার পরীক্ষায় দেখা গেছে যে কাইলের অ্যাপ্রোচ (অর্ডার (এন)) ড্রাজাসের দ্বারা নির্ধারিত র্যান্ডম সূচকগুলি (অর্ডার (কে)) প্রস্তাব দেওয়ার জন্য একটি সেট ব্যবহারের চেয়ে অনেকগুণ ধীর। প্রাক্তন এলোমেলো সংখ্যা জেনারেটরে আরও অনেক কল করে, এবং আইটেমগুলি দিয়ে আরও বারবার পুনরাবৃত্তি করে।

আমার বাস্তবায়নের লক্ষ্যগুলি ছিল:

1) কোনও আইএনলিস্টের কোনও আইলিস্ট না থাকলে পুরো তালিকাটি উপলব্ধি করবেন না। যদি আমাকে একটি জিলিয়ন আইটেমের ক্রম দেওয়া হয় তবে আমি স্মরণশক্তি ছাড়তে চাই না। অন-লাইন সমাধানের জন্য কাইলের পদ্ধতির ব্যবহার করুন।

2) যদি আমি বলতে পারি যে এটি একটি আইলিস্ট, তবে ড্রাজাসের অ্যাপ্রোচ ব্যবহার করুন, একটি মোচড় দিয়ে। কে যদি এন এর অর্ধেকের বেশি হয় তবে আমি বার বার অনেক এলোমেলো সূচকগুলি বেছে নিই এবং সেগুলি এড়িয়ে যেতে হবে বলে আমি ছিটকে যাওয়ার ঝুঁকি নিয়েছি। সুতরাং আমি সূচকগুলি না রাখার জন্য একটি তালিকা রচনা করেছি।

3) আমি গ্যারান্টি দিচ্ছি যে আইটেমগুলি যেভাবে सामना করেছিল সেগুলি একই ক্রমে ফিরে আসবে। কাইলের অ্যালগরিদমের কোনও পরিবর্তন দরকার হয়নি। ড্রজাউসের অ্যালগরিদমটির প্রয়োজন ছিল যে আমি এলোমেলো সূচকগুলি বেছে নেওয়া হয়েছে সেই ক্রমে আইটেমগুলি নির্গত করতে পারি না। আমি সমস্ত সূচকগুলি একটি সাজানোসেটে সংগ্রহ করি, তারপরে সাজানো সূচী ক্রমে আইটেমগুলি প্রেরণ করি।

৪) কে যদি এন এর সাথে তুলনা করে বড় হয় এবং আমি সেটটির ইন্দ্রিয়টি উল্টে রাখি, তবে আমি সমস্ত আইটেম গণনা করি এবং সূচকটি সেটে না থাকলে পরীক্ষা করি। এর অর্থ হ'ল আমি অর্ডার (কে) রানের সময়টি হারাব, তবে যেহেতু কে এই ক্ষেত্রে N এর নিকটবর্তী, তাই আমি খুব বেশি হারাতে পারি না।

কোডটি এখানে:

    /// <summary>
    /// Takes k elements from the next n elements at random, preserving their order.
    /// 
    /// If there are fewer than n elements in items, this may return fewer than k elements.
    /// </summary>
    /// <typeparam name="TElem">Type of element in the items collection.</typeparam>
    /// <param name="items">Items to be randomly selected.</param>
    /// <param name="k">Number of items to pick.</param>
    /// <param name="n">Total number of items to choose from.
    /// If the items collection contains more than this number, the extra members will be skipped.
    /// If the items collection contains fewer than this number, it is possible that fewer than k items will be returned.</param>
    /// <returns>Enumerable over the retained items.
    /// 
    /// See http://stackoverflow.com/questions/48087/select-a-random-n-elements-from-listt-in-c-sharp for the commentary.
    /// </returns>
    public static IEnumerable<TElem> TakeRandom<TElem>(this IEnumerable<TElem> items, int k, int n)
    {
        var r = new FastRandom();
        var itemsList = items as IList<TElem>;

        if (k >= n || (itemsList != null && k >= itemsList.Count))
            foreach (var item in items) yield return item;
        else
        {  
            // If we have a list, we can infer more information and choose a better algorithm.
            // When using an IList, this is about 7 times faster (on one benchmark)!
            if (itemsList != null && k < n/2)
            {
                // Since we have a List, we can use an algorithm suitable for Lists.
                // If there are fewer than n elements, reduce n.
                n = Math.Min(n, itemsList.Count);

                // This algorithm picks K index-values randomly and directly chooses those items to be selected.
                // If k is more than half of n, then we will spend a fair amount of time thrashing, picking
                // indices that we have already picked and having to try again.   
                var invertSet = k >= n/2;  
                var positions = invertSet ? (ISet<int>) new HashSet<int>() : (ISet<int>) new SortedSet<int>();

                var numbersNeeded = invertSet ? n - k : k;
                while (numbersNeeded > 0)
                    if (positions.Add(r.Next(0, n))) numbersNeeded--;

                if (invertSet)
                {
                    // positions contains all the indices of elements to Skip.
                    for (var itemIndex = 0; itemIndex < n; itemIndex++)
                    {
                        if (!positions.Contains(itemIndex))
                            yield return itemsList[itemIndex];
                    }
                }
                else
                {
                    // positions contains all the indices of elements to Take.
                    foreach (var itemIndex in positions)
                        yield return itemsList[itemIndex];              
                }
            }
            else
            {
                // Since we do not have a list, we will use an online algorithm.
                // This permits is to skip the rest as soon as we have enough items.
                var found = 0;
                var scanned = 0;
                foreach (var item in items)
                {
                    var rand = r.Next(0,n-scanned);
                    if (rand < k - found)
                    {
                        yield return item;
                        found++;
                    }
                    scanned++;
                    if (found >= k || scanned >= n)
                        break;
                }
            }
        }  
    } 

আমি একটি বিশেষায়িত র্যান্ডম নম্বর জেনারেটর ব্যবহার করি তবে আপনি চাইলে কেবল সি # র র্যান্ডম ব্যবহার করতে পারেন। ( ফাস্টআরন্ডমটি কলিন গ্রিন দ্বারা রচিত এবং শার্পনেট অংশ। এটির সময়কাল 2 ^ 128-1 যা অনেকগুলি আরএনজির চেয়ে ভাল)

এখানে ইউনিট পরীক্ষা রয়েছে:

[TestClass]
public class TakeRandomTests
{
    /// <summary>
    /// Ensure that when randomly choosing items from an array, all items are chosen with roughly equal probability.
    /// </summary>
    [TestMethod]
    public void TakeRandom_Array_Uniformity()
    {
        const int numTrials = 2000000;
        const int expectedCount = numTrials/20;
        var timesChosen = new int[100];
        var century = new int[100];
        for (var i = 0; i < century.Length; i++)
            century[i] = i;

        for (var trial = 0; trial < numTrials; trial++)
        {
            foreach (var i in century.TakeRandom(5, 100))
                timesChosen[i]++;
        }
        var avg = timesChosen.Average();
        var max = timesChosen.Max();
        var min = timesChosen.Min();
        var allowedDifference = expectedCount/100;
        AssertBetween(avg, expectedCount - 2, expectedCount + 2, "Average");
        //AssertBetween(min, expectedCount - allowedDifference, expectedCount, "Min");
        //AssertBetween(max, expectedCount, expectedCount + allowedDifference, "Max");

        var countInRange = timesChosen.Count(i => i >= expectedCount - allowedDifference && i <= expectedCount + allowedDifference);
        Assert.IsTrue(countInRange >= 90, String.Format("Not enough were in range: {0}", countInRange));
    }

    /// <summary>
    /// Ensure that when randomly choosing items from an IEnumerable that is not an IList, 
    /// all items are chosen with roughly equal probability.
    /// </summary>
    [TestMethod]
    public void TakeRandom_IEnumerable_Uniformity()
    {
        const int numTrials = 2000000;
        const int expectedCount = numTrials / 20;
        var timesChosen = new int[100];

        for (var trial = 0; trial < numTrials; trial++)
        {
            foreach (var i in Range(0,100).TakeRandom(5, 100))
                timesChosen[i]++;
        }
        var avg = timesChosen.Average();
        var max = timesChosen.Max();
        var min = timesChosen.Min();
        var allowedDifference = expectedCount / 100;
        var countInRange =
            timesChosen.Count(i => i >= expectedCount - allowedDifference && i <= expectedCount + allowedDifference);
        Assert.IsTrue(countInRange >= 90, String.Format("Not enough were in range: {0}", countInRange));
    }

    private IEnumerable<int> Range(int low, int count)
    {
        for (var i = low; i < low + count; i++)
            yield return i;
    }

    private static void AssertBetween(int x, int low, int high, String message)
    {
        Assert.IsTrue(x > low, String.Format("Value {0} is less than lower limit of {1}. {2}", x, low, message));
        Assert.IsTrue(x < high, String.Format("Value {0} is more than upper limit of {1}. {2}", x, high, message));
    }

    private static void AssertBetween(double x, double low, double high, String message)
    {
        Assert.IsTrue(x > low, String.Format("Value {0} is less than lower limit of {1}. {2}", x, low, message));
        Assert.IsTrue(x < high, String.Format("Value {0} is more than upper limit of {1}. {2}", x, high, message));
    }
}

পরীক্ষায় কোন ত্রুটি নেই? আপনার if (itemsList != null && k < n/2)অর্থ যা if invertSetসর্বদা অভ্যন্তরের অভ্যন্তরে থাকে falseযার অর্থ যে যুক্তি কখনও ব্যবহৃত হয় না।
নেটমেজ

4

@ এর এর উত্তর থেকে প্রসারিত, যদি কেউ অর্ডারবাইয়ের সম্ভাব্য বিভিন্ন প্রয়োগ সম্পর্কে উদ্বিগ্ন থাকে তবে এটি নিরাপদ হওয়া উচিত:

// Instead of this
YourList.OrderBy(x => rnd.Next()).Take(5)

// Temporarily transform 
YourList
    .Select(v => new {v, i = rnd.Next()}) // Associate a random index to each entry
    .OrderBy(x => x.i).Take(5) // Sort by (at this point fixed) random index 
    .Select(x => x.v); // Go back to enumerable of entry

3

এটিই প্রথম যেটি আমি প্রথম কাটতে পেরেছি তা সবচেয়ে ভাল:

public List<String> getRandomItemsFromList(int returnCount, List<String> list)
{
    List<String> returnList = new List<String>();
    Dictionary<int, int> randoms = new Dictionary<int, int>();

    while (randoms.Count != returnCount)
    {
        //generate new random between one and total list count
        int randomInt = new Random().Next(list.Count);

        // store this in dictionary to ensure uniqueness
        try
        {
            randoms.Add(randomInt, randomInt);
        }
        catch (ArgumentException aex)
        {
            Console.Write(aex.Message);
        } //we can assume this element exists in the dictonary already 

        //check for randoms length and then iterate through the original list 
        //adding items we select via random to the return list
        if (randoms.Count == returnCount)
        {
            foreach (int key in randoms.Keys)
                returnList.Add(list[randoms[key]]);

            break; //break out of _while_ loop
        }
    }

    return returnList;
}

1 - মোট তালিকার গণনা এবং এরপরে র্যান্ডমগুলির একটি তালিকা ব্যবহার করে তালিকায় সেই আইটেমগুলি টানাই সেরা উপায় বলে মনে হয়, তবে স্বাতন্ত্র্যতা নিশ্চিত করতে অভিধান ব্যবহার করা এমন কিছু যা আমি এখনও ম্লান করছি।

এছাড়াও নোট করুন আমি একটি স্ট্রিং তালিকা ব্যবহার করেছি, প্রয়োজন অনুযায়ী প্রতিস্থাপন করুন।


1
প্রথম শটে কাজ করেছেন!
সংগম

3

আমি যে সহজ সমাধানটি ব্যবহার করি (বৃহত তালিকার পক্ষে সম্ভবত এটি ভাল নয়): অস্থায়ী তালিকায় তালিকাটি অনুলিপি করুন, তারপরে লুপে এলোমেলোভাবে টেম্প তালিকা থেকে আইটেমটি নির্বাচন করুন এবং এটি অস্থায়ী তালিকা তৈরি করার সময় নির্বাচিত আইটেমের তালিকায় রাখুন (সুতরাং এটি হতে পারে না) reselected)।

উদাহরণ:

List<Object> temp = OriginalList.ToList();
List<Object> selectedItems = new List<Object>();
Random rnd = new Random();
Object o;
int i = 0;
while (i < NumberOfSelectedItems)
{
            o = temp[rnd.Next(temp.Count)];
            selectedItems.Add(o);
            temp.Remove(o);
            i++;
 }

একটি তালিকার মাঝখানে থেকে প্রায়শই সরিয়ে ফেলা ব্যয়বহুল হবে। আপনি অনেকগুলি অপসারণের প্রয়োজন বোধ করে একটি অ্যালগরিদমের জন্য একটি লিঙ্কযুক্ত তালিকা ব্যবহার করে বিবেচনা করতে পারেন। বা সমতুল্যভাবে, মুছে ফেলা আইটেমটি একটি নাল মান দিয়ে প্রতিস্থাপন করুন, তবে আপনি ইতিমধ্যে মুছে ফেলা আইটেমগুলি বেছে নেওয়ার সাথে সাথে আপনি কিছুটা ছোঁড়াবেন again
পল চেরনোক

3

জন শেডলেটস্কি উল্লেখ করেছেন যে এখানে ফিশার-ইয়েটস সাফলের উপর ভিত্তি করে আপনার একটি বাস্তবায়ন রয়েছে যার অ্যালগরিদম জটিলতা হ'ল (এন) যেখানে এন সাবসেট বা নমুনা আকারের পরিবর্তে তালিকার আকারের পরিবর্তে জন শেডলেটস্কি উল্লেখ করেছেন।

public static IEnumerable<T> GetRandomSample<T>(this IList<T> list, int sampleSize)
{
    if (list == null) throw new ArgumentNullException("list");
    if (sampleSize > list.Count) throw new ArgumentException("sampleSize may not be greater than list count", "sampleSize");
    var indices = new Dictionary<int, int>(); int index;
    var rnd = new Random();

    for (int i = 0; i < sampleSize; i++)
    {
        int j = rnd.Next(i, list.Count);
        if (!indices.TryGetValue(j, out index)) index = j;

        yield return list[index];

        if (!indices.TryGetValue(i, out index)) index = i;
        indices[j] = index;
    }
}

2

কাইলের উত্তরের ভিত্তিতে, এখানে আমার সি # বাস্তবায়ন।

/// <summary>
/// Picks random selection of available game ID's
/// </summary>
private static List<int> GetRandomGameIDs(int count)
{       
    var gameIDs = (int[])HttpContext.Current.Application["NonDeletedArcadeGameIDs"];
    var totalGameIDs = gameIDs.Count();
    if (count > totalGameIDs) count = totalGameIDs;

    var rnd = new Random();
    var leftToPick = count;
    var itemsLeft = totalGameIDs;
    var arrPickIndex = 0;
    var returnIDs = new List<int>();
    while (leftToPick > 0)
    {
        if (rnd.Next(0, itemsLeft) < leftToPick)
        {
            returnIDs .Add(gameIDs[arrPickIndex]);
            leftToPick--;
        }
        arrPickIndex++;
        itemsLeft--;
    }

    return returnIDs ;
}

2

এই পদ্ধতিটি কাইলের সমতুল্য হতে পারে।

বলুন যে আপনার তালিকাটি আকারের এন এবং আপনি কে উপাদান চান।

Random rand = new Random();
for(int i = 0; k>0; ++i) 
{
    int r = rand.Next(0, n-i);
    if(r<k) 
    {
        //include element i
        k--;
    }
} 

একটি যাদুমন্ত্র মত কাজ করে :)

-আলেক্স গিলবার্ট


1
এটা আমার সমান দেখাচ্ছে। অনুরূপ তুলনা stackoverflow.com/a/48141/2449863
DCShannon

1

কেন এই জাতীয় কিছু না:

 Dim ar As New ArrayList
    Dim numToGet As Integer = 5
    'hard code just to test
    ar.Add("12")
    ar.Add("11")
    ar.Add("10")
    ar.Add("15")
    ar.Add("16")
    ar.Add("17")

    Dim randomListOfProductIds As New ArrayList

    Dim toAdd As String = ""
    For i = 0 To numToGet - 1
        toAdd = ar(CInt((ar.Count - 1) * Rnd()))

        randomListOfProductIds.Add(toAdd)
        'remove from id list
        ar.Remove(toAdd)

    Next
'sorry i'm lazy and have to write vb at work :( and didn't feel like converting to c#

1

এটি মনে করার চেয়ে অনেক কঠিন। জেফের দুর্দান্ত আর্টিকেল "শাফলিং" দেখুন ।

আমি সি # কোড সহ সেই বিষয়ে খুব ছোট একটি নিবন্ধ লিখেছিলাম :
প্রদত্ত অ্যারের N উপাদানগুলির এলোমেলো উপসেটটি ফিরিয়ে দিন


1

লক্ষ্য: নকল ছাড়াই সংগ্রহের উত্স থেকে N নম্বর আইটেম নির্বাচন করুন। আমি যে কোনও জেনেরিক সংগ্রহের জন্য একটি এক্সটেনশন তৈরি করেছি। আমি এটি কীভাবে করেছি তা এখানে:

public static class CollectionExtension
{
    public static IList<TSource> RandomizeCollection<TSource>(this IList<TSource> source, int maxItems)
    {
        int randomCount = source.Count > maxItems ? maxItems : source.Count;
        int?[] randomizedIndices = new int?[randomCount];
        Random random = new Random();

        for (int i = 0; i < randomizedIndices.Length; i++)
        {
            int randomResult = -1;
            while (randomizedIndices.Contains((randomResult = random.Next(0, source.Count))))
            {
                //0 -> since all list starts from index 0; source.Count -> maximum number of items that can be randomize
                //continue looping while the generated random number is already in the list of randomizedIndices
            }

            randomizedIndices[i] = randomResult;
        }

        IList<TSource> result = new List<TSource>();
        foreach (int index in randomizedIndices)
            result.Add(source.ElementAt(index));

        return result;
    }
}

0

আমি সম্প্রতি টাইলারের পয়েন্ট 1 এর অনুরূপ ধারণা ব্যবহার করে আমার প্রকল্পে এটি করেছি ।
আমি প্রচুর প্রশ্ন লোড করছিলাম এবং এলোমেলোভাবে পাঁচটি নির্বাচন করছিলাম। বাছাই একটি আইসি কম্পিউটারে ব্যবহার করে অর্জিত হয়েছিল ।
সমস্ত প্রশ্ন প্রশ্নাবলীর তালিকায় লোড হয়েছিল, তারপরে তালিকার ক্রম ফাংশন এবং নির্বাচিত প্রথম কে উপাদানগুলির সাহায্যে বাছাই করা হয়েছিল।

    private class QuestionSorter : IComparable<QuestionSorter>
    {
        public double SortingKey
        {
            get;
            set;
        }

        public Question QuestionObject
        {
            get;
            set;
        }

        public QuestionSorter(Question q)
        {
            this.SortingKey = RandomNumberGenerator.RandomDouble;
            this.QuestionObject = q;
        }

        public int CompareTo(QuestionSorter other)
        {
            if (this.SortingKey < other.SortingKey)
            {
                return -1;
            }
            else if (this.SortingKey > other.SortingKey)
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }
    }

ব্যবহার:

    List<QuestionSorter> unsortedQuestions = new List<QuestionSorter>();

    // add the questions here

    unsortedQuestions.Sort(unsortedQuestions as IComparer<QuestionSorter>);

    // select the first k elements

0

এখানে আমার পদ্ধতির (সম্পূর্ণ পাঠ্য এখানে http://krkadev.blogspot.com/2010/08/random-numbers-without-repetition.html )।

এটি ও (এন) এর পরিবর্তে ও (কে) এ চালানো উচিত, যেখানে কে ওয়ান্টেড এলিমেন্টের সংখ্যা এবং এনটি তালিকা থেকে পছন্দ করে নিন:

public <T> List<T> take(List<T> source, int k) {
 int n = source.size();
 if (k > n) {
   throw new IllegalStateException(
     "Can not take " + k +
     " elements from a list with " + n +
     " elements");
 }
 List<T> result = new ArrayList<T>(k);
 Map<Integer,Integer> used = new HashMap<Integer,Integer>();
 int metric = 0;
 for (int i = 0; i < k; i++) {
   int off = random.nextInt(n - i);
   while (true) {
     metric++;
     Integer redirect = used.put(off, n - i - 1);
     if (redirect == null) {
       break;
     }
     off = redirect;
   }
   result.add(source.get(off));
 }
 assert metric <= 2*k;
 return result;
}

0

এটি গৃহীত সমাধানের মতো মার্জিত বা দক্ষ নয়, তবে এটি দ্রুত লিখে দেওয়া যায়। প্রথমে এড়াটি এলোমেলোভাবে স্থির করুন, তারপরে প্রথম কে উপাদান নির্বাচন করুন। অজগরে,

import numpy

N = 20
K = 5

idx = np.arange(N)
numpy.random.shuffle(idx)

print idx[:K]

0

আমি একটি এক্সটেনশন পদ্ধতি ব্যবহার করব।

    public static IEnumerable<T> TakeRandom<T>(this IEnumerable<T> elements, int countToTake)
    {
        var random = new Random();

        var internalList = elements.ToList();

        var selected = new List<T>();
        for (var i = 0; i < countToTake; ++i)
        {
            var next = random.Next(0, internalList.Count - selected.Count);
            selected.Add(internalList[next]);
            internalList[next] = internalList[internalList.Count - selected.Count];
        }
        return selected;
    }

0
public static IEnumerable<T> GetRandom<T>(this IList<T> list, int count, Random random)
    {
        // Probably you should throw exception if count > list.Count
        count = Math.Min(list.Count, count);

        var selectedIndices = new SortedSet<int>();

        // Random upper bound
        int randomMax = list.Count - 1;

        while (selectedIndices.Count < count)
        {
            int randomIndex = random.Next(0, randomMax);

            // skip over already selected indeces
            foreach (var selectedIndex in selectedIndices)
                if (selectedIndex <= randomIndex)
                    ++randomIndex;
                else
                    break;

            yield return list[randomIndex];

            selectedIndices.Add(randomIndex);
            --randomMax;
        }
    }

স্মৃতি: ~ গণনা
জটিলতা: হে (গণনা 2 )


0

যখন এন খুব বড় হয়, স্বাভাবিক পদ্ধতি যা এলোমেলোভাবে এন সংখ্যাগুলিকে বদল করে এবং নির্বাচন করে, বলে, প্রথম কে সংখ্যাগুলি, স্থান জটিলতার কারণে নিষিদ্ধ হতে পারে। নিম্নলিখিত অ্যালগরিদমের সময় ও স্থান উভয়ই জটিলতার জন্য কেবল ও (কে) প্রয়োজন।

http://arxiv.org/abs/1512.00501

def random_selection_indices(num_samples, N):
    modified_entries = {}
    seq = []
    for n in xrange(num_samples):
        i = N - n - 1
        j = random.randrange(i)

        # swap a[j] and a[i] 
        a_j = modified_entries[j] if j in modified_entries else j 
        a_i = modified_entries[i] if i in modified_entries else i

        if a_i != j:
            modified_entries[j] = a_i   
        elif j in modified_entries:   # no need to store the modified value if it is the same as index
            modified_entries.pop(j)

        if a_j != i:
            modified_entries[i] = a_j 
        elif i in modified_entries:   # no need to store the modified value if it is the same as index
            modified_entries.pop(i)
        seq.append(a_j)
    return seq

0

বড় তালিকাগুলি সহ লাইনকিউ ব্যবহার করা (যখন প্রতিটি উপাদানকে স্পর্শ করা ব্যয়বহুল) এবং যদি আপনি নকলের সম্ভাবনা নিয়ে বেঁচে থাকতে পারেন:

new int[5].Select(o => (int)(rnd.NextDouble() * maxIndex)).Select(i => YourIEnum.ElementAt(i))

আমার ব্যবহারের জন্য আমার 100.000 উপাদানগুলির একটি তালিকা ছিল এবং আমি তাদের পুরো তালিকায় একটি রেন্ডের তুলনায় সময়টিকে প্রায় অর্ধেক (বা আরও ভাল) ডিবি থেকে টেনে আছি বলে।

একটি বৃহত তালিকা থাকা নকলের পক্ষে প্রতিকূলতাকে হ্রাস করবে।


এই সমাধানে বারবার উপাদান থাকতে পারে !! গর্ত তালিকার এলোমেলোভাবে নাও থাকতে পারে।
এক্সেলওয়াস

হুম। সত্য। যেখানে আমি এটি ব্যবহার করি, তাতে কিছু আসে যায় না। যে প্রতিফলিত উত্তর সম্পাদনা।
ওল্ফ 5

-1

এটি আপনার সমস্যার সমাধান করবে

var entries=new List<T>();
var selectedItems = new List<T>();


                for (var i = 0; i !=10; i++)
                {
                    var rdm = new Random().Next(entries.Count);
                        while (selectedItems.Contains(entries[rdm]))
                            rdm = new Random().Next(entries.Count);

                    selectedItems.Add(entries[rdm]);
                }

যদিও এটি প্রশ্নের উত্তর দিতে পারে, এই কোড ব্লক কীভাবে প্রশ্নের উত্তর দেয় তার একটি ব্যাখ্যা অন্তর্ভুক্ত করার জন্য আপনার উত্তরটি সম্পাদনা করা উচিত । এটি প্রসঙ্গ সরবরাহ করতে সহায়তা করে এবং আপনার উত্তরটি ভবিষ্যতের পাঠকদের জন্য আরও কার্যকর করে তোলে।
হোপ্পিড্পিনুট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.