Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I was somewhat surprised in <a href="https://stackoverflow.com/questions/554587/is-there-an-easy-way-to-randomize-a-list-in-vb-net/">this thread</a> how many wrong answers were posted. Just for the sake of others who come up with a solution similar to the one posted by the OP, the following code <em>looks</em> correct:</p> <pre><code>int[] nums = new int[1000]; for (int i = 0; i &lt; nums.Length; i++) { nums[i] = i; } Random r = new Random(); Array.Sort&lt;int&gt;(nums, (x, y) =&gt; r.Next(-1, 2)); foreach(var num in nums) { Console.Write("{0} ", num); } </code></pre> <p>However, the code will throw an exception occasionally, but not always. That's what makes it fun to debug :) If you run it enough times, or execute the sort procedure in a loop 50 or so times, you'll get an error stating:</p> <p><code>IComparer (or the IComparable methods it relies upon) did not return zero when Array.Sort called x. CompareTo(x). x: '0' x's type: 'Int32' The IComparer: ''.</code></p> <p>In other words, the quick sort compared some number <code>x</code> to itself and got a non-zero result. The obvious solution to the code would be write:</p> <pre><code>Array.Sort&lt;int&gt;(nums, (x, y) =&gt; { if (x == y) return 0; else return r.NextDouble() &lt; 0.5 ? 1 : -1; }); </code></pre> <p>But even this doesn't work, because there are occasions where .NET compares 3 numbers against one another which return inconsistent results, such as A > B, B > C, and C > A (oops!). No matter if you use a Guid, GetHashCode, or any other randomly generated input, a solution like the one shown above is still wrong.</p> <hr> <p>With that being said, Fisher-Yates is the standard way of shuffling arrays, so there's no real reason to use IComparer in the first place. Fisher-Yates is O(n) whereas any implementation using IComparer uses a quicksort behinds the scenes which has a time-complexity of O(n log n). There's just no good reason not to use the well-known, efficient, standard algorithm to solve this kind of problem.</p> <p>However, if you really insist on using an IComparer and a rand, then apply your random data <em>before</em> you sort. This requires a projection of the data onto another object so you don't lose your random data:</p> <pre><code>using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Pair&lt;T, U&gt; { public T Item1 { get; private set; } public U Item2 { get; private set; } public Pair(T item1, U item2) { this.Item1 = item1; this.Item2 = item2; } } class Program { static void Main(string[] args) { Pair&lt;int, double&gt;[] nums = new Pair&lt;int, double&gt;[1000]; Random r = new Random(); for (int i = 0; i &lt; nums.Length; i++) { nums[i] = new Pair&lt;int, double&gt;(i, r.NextDouble()); } Array.Sort&lt;Pair&lt;int, double&gt;&gt;(nums, (x, y) =&gt; x.Item2.CompareTo(y.Item2)); foreach (var item in nums) { Console.Write("{0} ", item.Item1); } Console.ReadKey(true); } } } </code></pre> <p>Or get LINQy with your bad self:</p> <pre><code>Random r = new Random(); var nums = from x in Enumerable.Range(0, 1000) orderby r.NextDouble() select x; </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload