0

I have a List of chars, and I want to generate a random string from them.

var chars = new List<char>("abcdwhatever".ToCharArray());
var result = chars.OrderBy(new Guid()).Take(5).ToString();

As stated above I want to get random string.

Problem is it returns an error:

The type arguments for method Enumerable.OrderBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) cannot be inferred from the usage. Try specifying the type arguments explicitly.

Which is really curious because it's not the first time I'm trying to order a list, but this time, it refuses to work.

resharper
  • 1
  • 1

2 Answers2

2

You want this:

var rnd = new Random();
var result = chars.OrderBy(c => rnd.Next()).Take(5);

Guids are not guaranteed to be random, only unique. You should use a proper random number generator.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • 3
    Note that the behaviour of this solution isn't guaranteed either: there's nothing in the docs which says that the delegate is called exactly once per element. It works today and it's unlikely to break in the future, but it's technically relying on undocumented behaviour. – canton7 Jul 12 '21 at 08:51
  • Would calling the delegate more than once remove the randomness of this? It could probably change the order, but as we do not seem to care about the order... – Rafalon Jul 12 '21 at 08:54
  • @Rafalon - the issue with non-deterministic functions being called multiple times is that some sort routines assume that both `A – Damien_The_Unbeliever Jul 12 '21 at 08:56
  • but there are such answers everywhere, and with high votes, such as https://stackoverflow.com/questions/273313/randomize-a-listt – Lei Yang Jul 12 '21 at 08:58
  • @LeiYang - This is essentially random. The `Random` class itself insert a miniscule bias (see https://stackoverflow.com/questions/67888049/bug-in-nets-random-class) but the `OrderBy` method is perfectly fine to sort randomly. As canton points out this behaviour could change, but it would be a breaking change of the framework so it's super super unlikely. – Enigmativity Jul 12 '21 at 09:03
  • I don't see how it is possible to say anything about the randomness of the result, unless one knows exactly how OrderBy is implemented, and how it works on "this" machine. For a safe solution, I would first randomize, then sort. – Bent Tranberg Jul 12 '21 at 09:13
  • @BentTranberg - We know that `OrderBy`'s implementation is stable and only executes the lambda once for each value. It works fine and it is unlikely to change. – Enigmativity Jul 12 '21 at 09:14
  • 3
    The "correct" way to shuffle a list is Fisher-Yates, but that has been covered to death in other questions here on SO – canton7 Jul 12 '21 at 09:17
  • I would say "unlikely" doesn't cut it, but that's a minor point. I am not convinced there won't be a bias introduced by OrderBy. – Bent Tranberg Jul 12 '21 at 09:18
  • @canton7 - Yes, it has. In any case, `OrderBy` with a good PRNG is equivalent to Fisher-Yates and a damn sight easier to implement. – Enigmativity Jul 12 '21 at 09:19
-3

Maybe performance doesn't matter here, I don't know. But if it does though and supposed chars is a an IList<char> it'll run slightly faster using a plain vanilla for-loop

var r = new Random(DateTime.Now.Millisecond);
var randChars = new char[5];
for (var i = 0; i < 5; i++)
   randChars[i] = chars[r.Next(0, chars.Length)];
lidqy
  • 1,891
  • 1
  • 9
  • 11
  • Ah yes, must either remove each selected char from `chars`, or make sure all five random values are different from one another. – Dialecticus Jul 12 '21 at 09:23
  • What's the point in whatever char occurring more than once? The OrderBy thingy doesn't prevent this either (the source might have duplicates as well) and no one mentioned it to be a prerequiste. – lidqy Jul 12 '21 at 09:44
  • It's worse to do `new Random(DateTime.Now.Millisecond)` than `new Random()`. – Enigmativity Jul 12 '21 at 10:30
  • 2
    @lidqy - The `OrderBy` certainly does preserve each element. Your code it almost guaranteed to have duplicates and missing characters. – Enigmativity Jul 12 '21 at 10:32
  • @Enigmativity since the source 'chars' already contains duplicates, your plea seems pointless :D – lidqy Jul 12 '21 at 10:41
  • @Enigmativity Ordering a whole list of an uncertain Count in order to just randomly extract 5 of its chars doesn't seem clever to me. Pick the chars from 5 random indices is more straight-forward. – lidqy Jul 12 '21 at 10:45
  • @lidqy - Because the sample text contains two `e`s? – Enigmativity Jul 12 '21 at 10:45
  • @lidqy - "Pick the chars from 5 random indices is more straight-forward." - except for generating duplicates. Hence why a full sort works. – Enigmativity Jul 12 '21 at 10:46
  • @Enigmativity You generate duplicates as well and the condition that duplicates aren't allowed was mentioned exactely where? – lidqy Jul 12 '21 at 10:47
  • @lidqy - I do not generate duplicates. The OP's code also does not generate duplicates. – Enigmativity Jul 12 '21 at 10:49
  • @Enigmativity as long as the source contains duplicates, as it does in the sample, your unnecessary full sort might/will generate duplicates. So two 'e' that correspond to two 'e' in the source are good, while the same two 'e' generated by the algorithm are bad. Come one. – lidqy Jul 12 '21 at 10:54
  • @lidqy - What are you talking about? The full sort does not "generate" duplicates. It will "preserve" any existing duplicates. Any answer to this question should not generate duplicates. – Enigmativity Jul 12 '21 at 11:01
  • @Enigmativity No it's nowhere mentioned whether or not duplicates would be an issue. The OP didn't picture his use case. And since your code creates them as well - I already explained when - I seems very expedient to keep on repeating the same two simple reason concerning this trivial algorithm and implementation. – lidqy Jul 12 '21 at 11:10
  • @lidqy - Can you please demonstrate when my code would create duplicates? – Enigmativity Jul 12 '21 at 11:37
  • @lidqy - You certainly made the ***assertion*** but you didn't ***demonstrate***. – Enigmativity Jul 12 '21 at 22:53