C# LINQ表达式优化
我有下面的代码,我的目标是得到10个整数列表的随机结果集,其中每个列表包含4个整数,它们的相加超过80C# LINQ表达式优化,c#,linq,C#,Linq,我有下面的代码,我的目标是得到10个整数列表的随机结果集,其中每个列表包含4个整数,它们的相加超过80 var numList = new List<int> { 5, 20, 1, 7, 19, 3, 15, 60, 3, 21, 57, 9 }; var extractedList = (from n1 in numList from n2 in numList
var numList = new List<int> { 5, 20, 1, 7, 19, 3, 15, 60, 3, 21, 57, 9 };
var extractedList = (from n1 in numList
from n2 in numList
from n3 in numList
from n4 in numList
where n1 + n2 + n3 + n4 > 80
select new { n1, n2, n3, n4 }).ToList();
var numList=新列表{5,20,1,7,19,3,15,60,3,21,57,9};
var extractedList=(从numList中的n1开始)
从numList中的n2开始
从numList中的n3开始
从numList中的n4开始
其中n1+n2+n3+n4>80
选择新的{n1,n2,n3,n4});
现在我知道我可以很容易地将“.GetRange(startIndex,10)”添加到“.ToList()”中,但在这种情况下,提取的列表将有8799个项目,添加“GetRange”是否意味着只有10个项目加载到内存中,或者是否意味着先加载8799个项目,然后过滤到10个项目,我是LINQ的新手,所以我希望有一种有效的方法来实现这一点,因为我知道任何数字都不会超过200,使用8位字节有助于提高性能,任何关于这方面的建议都会很好。使用
采取方法只加载特定数量的项目,而不是全部项目,然后调用ToList
(from n1 in numList
from n2 in numList
from n3 in numList
from n4 in numList
where n1 + n2 + n3 + n4 > 80
select new { n1, n2, n3, n4 }).Take(10).ToList();
正如注释中已经指出的,这将始终给出相同的结果。您可以随机化列表,然后执行查询(而不是对数千个组合进行排序)
如果您只想要前10项,您可以使用:
var numList=新列表{5,20,1,7,19,3,15,60,3,21,57,9}
var extractedList = (from n1 in numList
from n2 in numList
from n3 in numList
from n4 in numList
where n1 + n2 + n3 + n4 > 80
select new { n1, n2, n3, n4 }).Take(10).ToList();
但是,它将始终产生相同的10项。如果您想继续使用LINQ:
var numList = new List<int> { 5, 20, 1, 7, 19, 3, 15, 60, 3, 21, 57, 9 };
Random rnd = new Random();
var extractedList = (from n1 in numList
from n2 in numList
from n3 in numList
from n4 in numList
where n1 + n2 + n3 + n4 > 80
select new
{
n1,
n2,
n3,
n4,
Rnd = rnd.NextDouble()
})
.OrderBy(z => z.Rnd)
.Take(10)
.ToList();
var numList=新列表{5,20,1,7,19,3,15,60,3,21,57,9};
随机rnd=新随机();
var extractedList=(从numList中的n1开始)
从numList中的n2开始
从numList中的n3开始
从numList中的n4开始
其中n1+n2+n3+n4>80
选择新的
{
n1,
n2,
n3,
n4,
Rnd=Rnd.NextDouble()
})
.OrderBy(z=>z.Rnd)
.Take(10)
.ToList();
请注意,我添加了一个随机参数,所以您不会总是得到相同的结果。如果您在列表中调用.GetRange,您必须首先拥有一个列表。
因此,整个查询将被枚举,结果将在一个列表中,然后从该列表中获取10项
如果您只需要这10个项目,就可以使用Skip and Take来处理查询本身
var extractedList = (from n1 in numList
from n2 in numList
from n3 in numList
from n4 in numList
where n1 + n2 + n3 + n4 > 80
select new { n1, n2, n3, n4 })
.Skip(startIndex).Take(10);
但是,如果要将结果拆分为长度为10的部分,则每次都会枚举整个查询,因此您不希望这样。在这种情况下,将整个结果存储在列表中(就像您在示例中所做的那样)会更好。使用Take
LINQ表达式
var numList = new List<int> { 5, 20, 1, 7, 19, 3, 15, 60, 3, 21, 57, 9 };
var extractedList = (from n1 in numList
from n2 in numList
from n3 in numList
from n4 in numList
where n1 + n2 + n3 + n4 > 80
select new { n1, n2, n3, n4 }).Take(10).ToList();
var numList=新列表{5,20,1,7,19,3,15,60,3,21,57,9};
var extractedList=(从numList中的n1开始)
从numList中的n2开始
从numList中的n3开始
从numList中的n4开始
其中n1+n2+n3+n4>80
选择新的{n1,n2,n3,n4});
这将只取通过您选择标准的前10个结果。要从随机化集合中获得该选择,OrderBy(x=>rnd.Next())将有所帮助,但这将对整个集合进行排序,因此这取决于您是否可以随机化集合而不影响性能(例如在后台)
或者,您可以考虑编写自己的ILIST扩展,如:
IList<T> GetRandomElements(this IList<T> me, int numElements)
{
var copyOfMe = new List<T>(me);
List<T> results = new List<T>();
Random rnd = new Random();
for(int i=0; i<numElements;i++)
{
if(copyOfMe.Count > 0)
{
int index = Random.Next(0,results.Count);
results.Add(copyOfMe[index]);
copyOfMe.Remove(index);
}
}
}
IList GetRandomElements(此IList me,整数元素)
{
var copyOfMe=新列表(me);
列表结果=新列表();
随机rnd=新随机();
对于(int i=0;i 0)
{
int index=Random.Next(0,results.Count);
结果。添加(copyOfMe[索引]);
删除(索引)的副本;
}
}
}
但是这确实需要一个IList输入(用于索引)。这里发布的其他解决方案的问题在于,它们是O(n4),因为它们在进行过滤之前会从列表中生成四个项目的所有可能组合。对于问题中给出的短名单来说,这可能很好,但不会扩大规模
例如,定义var numList=Enumerable.Range(10,50).ToList()代码>(因此列表中有50项)导致此处的其他解决方案需要大约15秒;下面更高效的版本只需几分之一秒
诀窍是定义一个生成器函数,Linq只调用完成查询所需的最小次数(尽管while(true)
使其看起来像一个无限循环,但yield return
使其每次返回一个值):
ToList
将创建一个包含所有项目的列表,然后您将从中提取十个项目并从中创建一个列表。请注意,像21,21,21,21
或20,21,20,21
或19,20,21,57
或57,22,20,19
int
这样的重复通常是在中使用的最有效的类型。请注意,这将始终产生前10项;所以numList应该随机化。此外,它还将优先于列表前面的项目。OrderBy子句是否会枚举整个集合以对其进行排序?
IList<T> GetRandomElements(this IList<T> me, int numElements)
{
var copyOfMe = new List<T>(me);
List<T> results = new List<T>();
Random rnd = new Random();
for(int i=0; i<numElements;i++)
{
if(copyOfMe.Count > 0)
{
int index = Random.Next(0,results.Count);
results.Add(copyOfMe[index]);
copyOfMe.Remove(index);
}
}
}
static IEnumerable<Tuple<int, int, int, int>> Generate(IList<int> list)
{
int max = list.Count;
Random rnd = new Random();
while (true)
{
yield return new Tuple<int, int, int, int>(
rnd.Next(max), rnd.Next(max), rnd.Next(max), rnd.Next(max));
}
}
var quickList = Generate(numList)
.Where(t => t.Item1 + t.Item2 + t.Item3 + t.Item4 > 80)
.Distinct().Take(10).ToList();