使用扩展方法向泛型列表添加随机功能






3.40/5 (3投票s)
扩展 IList
以包含一个洗牌方法和一个“随机选择元素”方法。
引言
.NET Framework 提供了大量用于操作列表的功能。然而,经常出现的需求是能够将列表重新排序为随机序列,或者从列表中随机选择一个元素。这两者都相对简单,并且可以通过在 IList<T>
上使用一对扩展方法来实现,这意味着它们将可用于任何 List<T>
或 ObservableCollection<T>
以及从它们派生的任何类。
注意:本文已更新,请滚动到页面底部查看历史记录。
选择随机元素
可以使用扩展方法实现一个选择随机元素的方法,但必须位于一个 static
类中。
需要注意的是,Random.Next
返回一个介于 0
和 list.Count – 1
之间的值,即小于指定的最大值(另外,我实际上有一个 Random
的扩展方法,可以使用包含参数值的返回值)。语句 default(T)
用于因为值类型不能设置为 null
(例如,int
与 int?
相对)。
private static Random random = new Random();
public static T GetRandom<T>(this IList<T> list)
{
if (list.Count == 0)
{
return default(T);
}
return list[random.Next(0, list.Count)];
}
重新排序列表
既然我们已经了解了 Random
的味道,那么如何操作列表中的元素呢? 同样,扩展方法提供了一种简洁的方法来做到这一点
public static void Shuffle <T>(this IList <T> list)
{
if (list.Count <= 1)
{
return; // nothing to do
}
for (int i = 0; i < list.Count; i++)
{
int newIndex = random.Next(0, list.Count);
// swap the two elements over
T x = list[i];
list[i] = list[newIndex];
list[newIndex] = x;
}
}
它的工作原理是循环遍历列表中的每个元素,并将其与随机选择位置的另一个元素交换。 请注意,与许多事情一样,当列表相对较小时,此代码可以正常工作,但讨论列表操作的优化超出了本文的范围。
结论
这些方法只是列表可以扩展以包含产生随机输出的功能的两种示例,并且通过将其放置在基础泛型接口上,可以实现跨大量类的重用。
历史
- 版本 1.0
- 首次发布
- 版本 1.1
- 更新了洗牌算法,使其真正随机
- 改进了示例