Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

EDIT:
Thanks to Mathew in comments, I managed to construct the extension method for generic array correctly:

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

But ultimately I'll play around with the Dmitry's answer and try to make these for IEnumerable. Thank you very much!

EDIT2:
Thanks to Zastai, I changed all methods so they work for both List and generic array:

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

public static IEquatable Random<IEquatable>(this IReadOnlyList<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 IReadOnlyList<T> list, int count)
{
    List<T> result = new();
    for (int i = 0; i < count; i++)
    {
        result.Add(list.Random());
    }
    return result;
}

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

Doesn't work for strings (as in "abcdefg".Random()), but for my needs it's not neccessary.

like image 249
Arkadiusz Galler Avatar asked Nov 29 '25 20:11

Arkadiusz Galler


1 Answers

IEnumerable is specifically just a sequence of values, and has no length.

IReadOnlyList on the other hand, is a list of values (so does have a length) and does not allow adding/removing values.

A .NET array implements both.

So if you change your extension methods to take IReadOnlyList<xxx> instead of List<xxx> they should automatically work on arrays too.

like image 50
Zastai Avatar answered Dec 02 '25 08:12

Zastai