Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.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# 如何划分LINQ到对象查询?_C#_.net_Indexing_Clr_Linq To Objects - Fatal编程技术网

C# 如何划分LINQ到对象查询?

C# 如何划分LINQ到对象查询?,c#,.net,indexing,clr,linq-to-objects,C#,.net,Indexing,Clr,Linq To Objects,这是一个资源分配问题。我的目标是运行查询以获取任何时间段的最高优先级班次 数据集非常大。在本例中,假设1000家公司有100个班次(尽管实际数据集更大)。它们都加载到内存中,我需要对它们运行一个LINQ to Objects查询: var topShifts = (from s in shifts where (from s2 in shifts where s2.CompanyId == s.Comp

这是一个资源分配问题。我的目标是运行查询以获取任何时间段的最高优先级班次

数据集非常大。在本例中,假设1000家公司有100个班次(尽管实际数据集更大)。它们都加载到内存中,我需要对它们运行一个LINQ to Objects查询:

    var topShifts =
            (from s in shifts
            where (from s2 in shifts
                   where s2.CompanyId == s.CompanyId && s.TimeSlot == s2.TimeSlot
                   orderby s2.Priority
                   select s2).First().Equals(s)
            select s).ToList();
问题是,如果不进行优化,LINQ to Objects将比较两个集中的每个对象,将所有1000 x 100与1000 x 100进行交叉连接,这相当于100亿(1000000000)次比较。我想要的是只比较每个公司内的对象(就像公司在SQL表中被索引一样)。这将产生1000组100 x 100对象,用于总计1000万(10000000)次比较。后者将随着公司数量的增长而线性扩展,而不是指数扩展

像这样的技术允许我这样做,但不幸的是,我没有在执行此查询的环境中使用自定义集合的特权。此外,我只希望在任何给定的数据集上运行此查询一次,因此持久索引的值是有限的。我希望使用一个扩展方法,该方法将按公司对数据进行分组,然后在每个组上运行表达式

完整示例代码:

public struct Shift
{
    public static long Iterations;

    private int companyId;
    public int CompanyId
    {
        get { Iterations++; return companyId; }
        set { companyId = value; }
    }

    public int Id;
    public int TimeSlot;
    public int Priority;
}

class Program
{
    static void Main(string[] args)
    {
        const int Companies = 1000;
        const int Shifts = 100;
        Console.WriteLine(string.Format("{0} Companies x {1} Shifts", Companies, Shifts));
        var timer = Stopwatch.StartNew();

        Console.WriteLine("Populating data");
        var shifts = new List<Shift>();
        for (int companyId = 0; companyId < Companies; companyId++)
        {
            for (int shiftId = 0; shiftId < Shifts; shiftId++)
            {
                shifts.Add(new Shift() { CompanyId = companyId, Id = shiftId, TimeSlot = shiftId / 3, Priority = shiftId % 5 });
            }
        }
        Console.WriteLine(string.Format("Completed in {0:n}ms", timer.ElapsedMilliseconds));
        timer.Restart();

        Console.WriteLine("Computing Top Shifts");
        var topShifts =
                (from s in shifts
                where (from s2 in shifts
                       where s2.CompanyId == s.CompanyId && s.TimeSlot == s2.TimeSlot
                       orderby s2.Priority
                       select s2).First().Equals(s)
                select s).ToList();
        Console.WriteLine(string.Format("Completed in {0:n}ms", timer.ElapsedMilliseconds));
        timer.Restart();

        Console.WriteLine("\nShifts:");
        foreach (var shift in shifts.Take(20))
        {
            Console.WriteLine(string.Format("C {0} Id {1} T {2} P{3}", shift.CompanyId, shift.Id, shift.TimeSlot, shift.Priority));
        }

        Console.WriteLine("\nTop Shifts:");
        foreach (var shift in topShifts.Take(10))
        {
            Console.WriteLine(string.Format("C {0} Id {1} T {2} P{3}", shift.CompanyId, shift.Id, shift.TimeSlot, shift.Priority));
        }

        Console.WriteLine(string.Format("\nTotal Comparisons: {0:n}", Shift.Iterations/2));

        Console.WriteLine("Any key to continue");
        Console.ReadKey();
    }
}
公共结构移位
{
公共静态长迭代;
私人国际公司;
公共国际公司
{
获取{Iterations++;返回companyId;}
设置{companyId=value;}
}
公共int Id;
公共int时隙;
公共优先权;
}
班级计划
{
静态void Main(字符串[]参数)
{
const int Companies=1000;
常数int移位=100;
WriteLine(string.Format(“{0}公司x{1}班次”,公司,班次));
var timer=Stopwatch.StartNew();
Console.WriteLine(“填充数据”);
var shifts=新列表();
对于(int companyId=0;companyId
样本输出:

1000家公司x 100班
填充数据
在10.00ms内完成
计算顶移
在520721.00ms内完成

班次:
c0id0t0p0
c0id1t0p1
c0id2t0p2
c0id3t1p3
c0id4t1p4
c0id5t1p0
c0id6t2p1
c0id7t2p2
c0id8t2p3
c0id9t3p4
c0id10t3p0
c0id11t3p1
c0id12t4p2
c0id13t4p3
c0id14t4p4
c0id15t5p0
c0id16t5p1
c0id17t5p2
c0id18t6p3
c0id19t6p4

顶班:
c0id0t0p0
c0id5t1p0
c0id6t2p1
c0id10t3p0
c0id12t4p2
c0id15t5p0
c0id20t6p0
c0id21t7p1
c0id25t8p0
c0id27t9p2

总比较:1000000015.00
按任意键继续

问题:

  • 如何对查询进行分区(同时仍然作为单个LinQ查询执行),以便将比较从100亿降至1000万?
  • 有没有比子查询更有效的解决问题的方法?
    老实说,我有点不确定你想要什么,但是从阅读你的代码中,我会说你可以做一些类似的事情

    (from company in shifts.GroupBy(s=>s.CompanyID)
     let lowPriority = (from slot in company.GroupBy(s=>s.TimeSlot)
    select slot).OrderBy(s=>s.Priority).First()
     select lowPriority).ToList();
    

    您是否尝试过使用
    分组依据

    var topShifts =  from s in shifts
                     group s by new { 
                         CompanyId = s.CompanyId, 
                         TimeSlot = s.TimeSlot } into p
                     let temp = p.OrderBy(x => x.Priority).FirstOrDefault()
                     select new
                         {
                             CompanyId = temp.CompanyId,
                             TimeSlot = temp.TimeSlot,
                             Id = temp.Id,
                             Priority = temp.Priority
                         };
    
    怎么样

                var topShifts = from s in shifts.GroupBy(s => s.CompanyId)
                            from a in s.GroupBy(b => b.TimeSlot)
                            select a.OrderBy(p => p.Priority).First();
    
    似乎得到了相同的输出,但比较了100015次


    通过@Geoff的编辑,他刚刚将我的比较结果减半:-)

    得到了不同的结果集,但我仍在努力找出答案why@David. 现在开始工作了。我还按照
    shiftId
    进行分组。Speed wise和您的答案类似,所以我想这正是您喜欢的代码风格。为noob很好地解释了这个问题。更像这样:-)+1谢谢。事实上,我有一个后续(即将推出),将重点放在使用范围而不是时隙ID匹配时间上。为了避免问题过于复杂,我想单独发布它。作为参考,它不使用时隙ID。一旦我引入了重叠检测,我仍然很难弄清楚如何进行分组,但我相信分组也是解决这个问题的答案。+1我认为我的答案无论如何都不会超过这一点:)这在我的电脑上5毫秒就完成了。谢谢。这就解决了这个问题,并且运行速度非常快(如果我添加。