C#: Elegant code for getting a random value from an IEnumerable

前端 未结 4 935
暗喜
暗喜 2020-12-10 11:46

In Python, I can do this:

>>> import random
>>> ints = [1,2,3]
>>> random.choice(ints)
3

In C# the first thing I

相关标签:
4条回答
  • 2020-12-10 11:55

    How about something simple and readable:

    ints[randgen.Next(ints.Length)];
    

    Seriously, why obfuscate your code with lambdas .OrderBy and .First and .Skip and so forth!?

    0 讨论(0)
  • 2020-12-10 11:59

    Here's a couple extension methods for you:

    public static T RandomElement<T>(this IEnumerable<T> enumerable)
    {
        return enumerable.RandomElementUsing<T>(new Random());
    }
    
    public static T RandomElementUsing<T>(this IEnumerable<T> enumerable, Random rand)
    {
        int index = rand.Next(0, enumerable.Count());
        return enumerable.ElementAt(index);
    }
    
    // Usage:
    var ints = new int[] { 1, 2, 3 };
    int randomInt = ints.RandomElement();
    
    // If you have a preexisting `Random` instance, rand, use it:
    // this is important e.g. if you are in a loop, because otherwise you will create new
    // `Random` instances every time around, with nearly the same seed every time.
    int anotherRandomInt = ints.RandomElementUsing(rand);
    

    For a general IEnumerable<T>, this will be O(n), since that is the complexity of .Count() and a random .ElementAt() call; however, both special-case for arrays and lists, so in those cases it will be O(1).

    0 讨论(0)
  • 2020-12-10 12:07

    No, that's basically the easiest way. Of course, that's only semi-random, but I think it fits most needs.

    EDIT: Huge Point Here...

    If you only want ONE value randomly chosen from the list... then just do this:

    var myRandomValue = ints[(new Random()).Next(0, ints.Length)];
    

    That's a O(1) operation.

    0 讨论(0)
  • 2020-12-10 12:09

    Sorting will be far less efficient. Just use Skip(n) and First():

    var randgen = new Random();
    var ints = new int[] { 1, 2, 3};
    

    ints.Skip(x=> randgen.Next(0, ints.Count())).First();

    ints.ElementAt(x=> randgen.Next(0, ints.Count()));
    
    0 讨论(0)
提交回复
热议问题