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;
}

不适用于字符串(如"abcdefg".Random()),但对于我的需要,它不是必需的.

推荐答案

IEnumerable只是一个值序列,没有长度.

另一方面,IReadOnlyList是一个值列表(因此有长度),不允许添加/删除值.

A.NET数组同时实现了这两个功能.

因此,如果您将扩展方法更改为IReadOnlyList<xxx>而不是List<xxx>,那么它们也应该自动处理array.

Csharp相关问答推荐

如何从C#中有类.x和类.y的类列表中映射List(字符串x,字符串y)?

是否可以将gltf转换为字节数组,然后将字节数组转换回文件?

ASP.NET核心结果.文件vs结果.流

WPF Windows初始化正在锁定. Net 8中分离的线程

. NET WireMock拒绝PostAsJsonAsync序列化

如何解决提交按钮后 Select 选项错误空参照异常

Cosmos SDK和Newtonsoft对静态只读记录的可能Mutations

.NET SDK包中的官方C#编译器在哪里?

单元测试:模拟返回空

如何使用MailKit删除邮箱?

C#中Java算法的类似功能

N层解决方案上的依赖注入-删除样板

在Windows Plesk上发布ASP.NET Core 7 Web API-错误:无法加载文件或程序集';Microsoft.Data.SqlClient';

使用动态键从请求体反序列化JSON

未显示详细信息的弹出对话框

C#Microsoft.CodeAnalysis.CSharp.Scriiting不等待并行.对于

将字符串类型日期输入(yyyy-mm-ddthh:mm:ss)转换为MM/dd/yyyy格式

如何在单击按钮后多次异步更新标签

具有嵌套属性的IGGroup

Xamarin.Forms中具有类似AspectFill的图像zoom 的水平滚动视图