Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

c# extension methods for generic array

I’m trying to make extension methods for generic array, so I could takeout random set of elements.
I made following extension methods for List<T> type and they work great, but I can’t work out how to do exactly the same for generic array:

public static T Random<T>(this List<T> list)
{
    return list[GameManager.instance.functions.RandomInt(list.Count - 1)];
}

public static IEquatable Random<IEquatable>(this List<IEquatable> list, List<IEquatable> hits)
{
    int rand = GameManager.instance.functions.RandomInt(list.Count - 1);
    while (hits.Exists(h => h.Equals(list[rand])))
        rand = GameManager.instance.functions.RandomInt(list.Count - 1);
    return list[rand];
}

public static List<T> Random<T>(this List<T> list, int count)
{
    List<T> result = new List<T>();
    for (int i = 0; i < count; i++)
    {
        result.Add(list.Random());
    }
    return result;
}

public static List<IEquatable> RandomUnique<IEquatable>(this List<IEquatable> list, int count)
{
    List<IEquatable> result = new List<IEquatable>();
    for (int i = 0; i < count; i++)
    {
        result.Add(list.Random(result));
    }
    return result;
}

I tried to rework the first method like this:

public static IEnumerable Random<IEnumerable>(this IEnumerable list)

but it doesn’t recognize list as an array so I can’t get to it’s length value.
I see a workaround, to do a List from Array, then get my random values and make array again, but it’s seems like too much action for just taking eg. 2 random from 4 elements array.
Please advise

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Instead of implementing extensions methods for List<T>, T[] etc. you can try implementing a
single routine for IEnumerable<T>, e.g.

public static partial class EnumerableExtensions {
  public static T Random<T>(this IEnumerable<T> source) {
    //DONE: do not forget to validate public methods' arguments
    if (source is null)
      throw new ArgumentNullException(nameof(source));

    // If enumerable is a collection (array, list) we can address items explictitly
    if (source is ICollection<T> collection) {
      if (collection.Count <= 0)
        throw new ArgumentOutOfRangeException(nameof(source), 
          $"Empty {nameof(source)} is not supported.");

      return collection[GameManager.instance.functions.RandomInt(collection.Count - 1)];
    }

    // In general case we have to materialize the enumeration
    var list = source.ToList();

    if (list.Count <= 0)
      throw new ArgumentOutOfRangeException(nameof(source), 
        $"Empty {nameof(source)} is not supported.");

    return list[GameManager.instance.functions.RandomInt(list.Count - 1)];
  }
}

Then you can use the same extension method with list, array etc.:

// Array
int demo1 = new int[] {4, 5, 6}.Random();
// List
double demo2 = new List<double>() {1.0. 3.0}.Random(); 
// String is not array or list but implements IEnumerable<char>
char demo3 = "abcdef".Random();
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading