C# 获取页面并合并到页面列表
我有一个列表,假设它包含1000项。最后,我想列出10个乘以100个项目的列表,内容如下:C# 获取页面并合并到页面列表,c#,linq,C#,Linq,我有一个列表,假设它包含1000项。最后,我想列出10个乘以100个项目的列表,内容如下: myList.Select(x => x.y).Take(100) (until list is empty) 因此,我希望Take(100)运行十次,因为该列表包含1000个项目,最后的列表包含10个列表,每个列表包含100个项目。您需要知道已获取的记录数,您可以跟踪该数字,并在查询时使用它 alreadyTaken = 0; while (alreadyTaken < 1000) {
myList.Select(x => x.y).Take(100) (until list is empty)
因此,我希望Take(100)运行十次,因为该列表包含1000个项目,最后的列表包含10个列表,每个列表包含100个项目。您需要知道已获取的记录数,您可以跟踪该数字,并在查询时使用它
alreadyTaken = 0;
while (alreadyTaken < 1000) {
var pagedList = myList.Select(x => x.y).Skip(alreadyTaken).Take(100);
...
alreadyTaken += 100;
}
alreadyTaken=0;
而(已经达到<1000){
var pagedList=myList.Select(x=>x.y).Skip(alreadyTaken).Take(100);
...
alreadyTaken+=100;
}
您需要知道您已经取得的记录的数量,您可以跟踪该数量,并在查询时使用它
alreadyTaken = 0;
while (alreadyTaken < 1000) {
var pagedList = myList.Select(x => x.y).Skip(alreadyTaken).Take(100);
...
alreadyTaken += 100;
}
alreadyTaken=0;
而(已经达到<1000){
var pagedList=myList.Select(x=>x.y).Skip(alreadyTaken).Take(100);
...
alreadyTaken+=100;
}
这可以通过简单的分页扩展方法实现
public static List<T> GetPage<T>(this List<T> dataSource, int pageIndex, int pageSize = 100)
{
return dataSource.Skip(pageIndex * pageSize)
.Take(pageSize)
.ToList();
}
publicstaticlist-GetPage(此列表数据源,intpageindex,intpagesize=100)
{
返回dataSource.Skip(pageIndex*pageSize)
.Take(页面大小)
.ToList();
}
当然,您可以将其扩展为接受和/或返回任何类型的
IEnumerable
,这可以通过简单的分页扩展方法实现
public static List<T> GetPage<T>(this List<T> dataSource, int pageIndex, int pageSize = 100)
{
return dataSource.Skip(pageIndex * pageSize)
.Take(pageSize)
.ToList();
}
publicstaticlist-GetPage(此列表数据源,intpageindex,intpagesize=100)
{
返回dataSource.Skip(pageIndex*pageSize)
.Take(页面大小)
.ToList();
}
当然,您可以扩展它来接受和/或返回任何类型的
IEnumerable
,正如已经发布的那样,您可以使用来执行循环和跳过某些元素和获取某些元素。这样,您就可以在每个for
循环中创建一个新查询。但是,如果您还想遍历这些查询中的每一个,则会出现一个问题,因为这将非常低效。假设您只有50个条目,并且希望在列表中每个循环包含10个元素。您将有5个循环正在进行
.跳过(0)。接受(10)
.跳过(10).拿(10)
.跳过(20).拿(10)
.跳过(30)。拿(10)
.跳过(40)。拿(10)
这里提出了两个问题
Skip
ing元素仍然会导致计算。在第一个查询中,您只计算所需的10个元素,但在第二个循环中,您计算了20个元素并丢弃了10个元素,依此类推。如果将所有5个循环相加,即使只有50个元素,也已经计算出10+20+30+40+50=150个元素。这将导致O(n^2)性能
不是每个IEnumerable都做上述事情。一些IEnumerable(例如数据库)可以优化跳过
,例如,它们在SQL查询中使用偏移量
(MySQL)定义。但这仍然不能解决问题。您仍然存在的主要问题是,您将创建5个不同的查询并执行所有5个查询。这五个问题现在需要的时间最多。因为对数据库的简单查询甚至比跳过一些内存元素或计算要慢得多
由于所有这些问题,如果您还想对每个循环中的每个查询求值,那么不使用带有多个.Skip(x)的for
循环是有意义的。相反,您的算法应该只遍历IEnumerable一次,执行查询一次,并在第一次迭代中返回前10个元素。下一次迭代返回接下来的10个元素,以此类推,直到元素用完为止
下面的扩展方法正是这样做的
public static IEnumerable<IReadOnlyList<T>> Combine<T>(this IEnumerable<T> source, int amount) {
var combined = new List<T>();
var counter = 0;
foreach ( var entry in source ) {
combined.Add(entry);
if ( ++counter >= amount ) {
yield return combined;
combined = new List<T>();
counter = 0;
}
}
if ( combined.Count > 0 )
yield return combined;
}
您将得到一个新的IEnumerable
,它只需通过枚举一次,即可将所有内容切成最多100个元素的块
只是为了说明性能可能有多大差异:
var numberCount = 100000;
var combineCount = 100;
var nums = Enumerable.Range(1, numberCount);
var count = 0;
// Bechmark with Combine() Extension
var swCombine = Stopwatch.StartNew();
var sumCombine = 0L;
var pages = nums.Combine(combineCount);
foreach ( var page in pages ) {
sumCombine += page.Sum();
count++;
}
swCombine.Stop();
Console.WriteLine("Count: {0} Sum: {1} Time Combine: {2}", count, sumCombine, swCombine.Elapsed);
// Doing it with .Skip(x).Take(y)
var swTakes = Stopwatch.StartNew();
count = 0;
var sumTaken = 0L;
var alreadyTaken = 0;
while ( alreadyTaken < numberCount ) {
sumTaken += nums.Skip(alreadyTaken).Take(combineCount).Sum();
alreadyTaken += combineCount;
count++;
}
swTakes.Stop();
Console.WriteLine("Count: {0} Sum: {1} Time Takes: {2}", count, sumTaken, swTakes.Elapsed);
通过这种方式,您将在单个查询中获得从200
到300
的元素。还有一个带有数据库的IEnumerable可以优化它,您只需要一个查询。所以如果您只想从IEnumerable
中获得特定范围的元素,那么您应该使用Skip
和Take
并像上面那样执行,而不是使用我提供的Combine
扩展方法。如前所述,您可以对循环和Skip
某些元素使用获取一些元素。这样,您就可以在每个for
循环中创建一个新查询。但是,如果您还想遍历这些查询中的每一个,则会出现一个问题,因为这将非常低效。假设您只有50个条目,并且希望在列表中每个循环包含10个元素。您将有5个循环正在进行
.跳过(0)。接受(10)
.跳过(10).拿(10)
.跳过(20).拿(10)
.跳过(30)。拿(10)
.跳过(40)。拿(10)
这里提出了两个问题
Skip
ing元素仍然会导致计算。在第一个查询中,您只计算所需的10个元素,但在第二个循环中,您计算了20个元素并丢弃了10个元素,依此类推。如果将所有5个循环相加,即使只有50个元素,也已经计算出10+20+30+40+50=150个元素。这将导致O(n^2)性能
不是每个IEnumerable都做上述事情。一些IEnumerable(例如数据库)可以优化跳过
,例如,它们在SQL查询中使用偏移量
(MySQL)定义。但这仍然不能解决问题。您仍然存在的主要问题是,您将创建5个不同的查询并执行所有5个查询。这五个问题现在需要的时间最多。因为对数据库的简单查询甚至比跳过一些内存元素或计算要慢得多
由于所有这些问题,如果您还想对每个l中的每个查询求值,那么不使用带有多个.Skip(x).Take(y)
的for
循环是有意义的