我正在努力学习LINQ,但一开始就很混乱!
我有一组具有颜色属性(MyColor)的项目。我有另一个所有颜色的集合(称为AvailableColors - 例如10个)。
我想从我的集合中尚不存在的AvailableColors中获取随机颜色。
我当前的C#代码只是一个随机颜色但是我想在LINQ中重写它以接收当前的颜色集合并从可能的选项中排除它们:
public MyColor GetRandomColour()
{
return AvailableColors[new Random().Next(0, AvailableColors.Count)];
}
所以它将采用现有的集合:
public MyColor GetRandomColour(ListOfSomethingWithColorProperty)
感谢您的任何指示!
答案 0 :(得分:2)
排除已使用的颜色意味着保存状态。您最好writing an iterator并使用yield
return
返回序列中的下一个随机颜色。这使您可以“记住”已使用的颜色。
如果您愿意,可以使用Linq的Take(1)
进行调用。
答案 1 :(得分:0)
// assumes Random object is available, preferrably a re-used instance
Color color = AvailableColors
.Except(myItems.Select(item => item.Color).Distinct())
.OrderBy(c => random.Next())
.FirstOrDefault();
可能不是非常有效,但也可能不是一个问题,因为少数项目。
另一种方法是事先对可用颜色进行一次随机排序,因此您可以按顺序排列。使用List<Color>
以便您可以在使用时删除元素,或者在每次拉动时保存当前索引。一旦列表耗尽或索引超过阵列的长度,请通知您的用户您已全部没有颜色。
答案 2 :(得分:0)
var rnd = new Random(); // don't keep recreating a Random object.
public MyColor GetRandomColour(List<Something> coll)
{
var len = rnd.Next(0, AvailableColors.Count- coll.Count);
return AvailableColors.Except(coll.Select(s=>s.MyColor)).Skip(len).First();
}
答案 3 :(得分:0)
我建议您Linq-minded
并创建一个好的,通用的IEnumerable<T>
扩展方法来完成您需要的繁重工作,然后您的GetRandomColor
函数更简单,您可以将扩展方法用于其他类似任务。
首先,定义这个扩展方法:
public static IEnumerable<T> SelectRandom<T>(this IEnumerable<T> @this, int take)
{
if (@this == null)
{
return null;
}
var count = @this.Count();
if (count == 0)
{
return Enumerable.Empty<T>();
}
var rnd = new Random();
return from _ in Enumerable.Range(0, take)
let index = rnd.Next(0, count)
select @this.ElementAt(index);
}
此功能允许您从任何IEnumerable<T>
中选择零个或多个随机选择的元素。
现在您的GetRandomColor
功能如下:
public static MyColor GetRandomColour()
{
return AvailableColors.SelectRandom(1).First();
}
public static MyColor GetRandomColour(IEnumerable<MyColor> except)
{
return AvailableColors.Except(except).SelectRandom(1).First();
}
第二个函数接受IEnumerable<MyColor>
以从可用颜色中排除,因此要调用此函数,您需要从项目集合中选择MyColor
属性。由于您没有指定此集合的类型,因此我认为最好使用IEnumerable<MyColor>
而不是组成类型或定义不必要的接口。
所以,调用代码现在看起来像这样:
var myRandomColor = GetRandomColour(collectionOfItems.Select(o => o.MyColor));
或者,您可以直接依赖Linq和新创建的扩展方法并执行此操作:
var myRandomColor =
AvailableColors
.Except(collectionOfItems.Select(o => o.MyColor))
.SelectRandom(1)
.First();
此替代方案更具可读性和可理解性,有助于代码的可维护性。请享用。
答案 4 :(得分:0)
从序列中选择随机元素有一种很好的方法。这里它被实现为一种扩展方法:
public static T Random<T>(this IEnumerable<T> enumerable)
{
var rng = new Random(Guid.NewGuid().GetHashCode());
int totalCount = 0;
T selected = default(T);
foreach (var data in enumerable)
{
int r = rng.Next(totalCount + 1);
if (r >= totalCount)
selected = data;
totalCount++;
}
return selected;
}
该方法使用以下事实:当迭代为1 / n时,在第m个选择第n个元素的概率。
使用此方法,您可以在一行中选择颜色:
var color = AvailableColors.Except(UsedColors).Random();