Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 获取页面并合并到页面列表_C#_Linq - Fatal编程技术网

C# 获取页面并合并到页面列表

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) {

我有一个列表,假设它包含1000项。最后,我想列出10个乘以100个项目的列表,内容如下:

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
    循环是有意义的