Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.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#_Performance_Linq - Fatal编程技术网

C# 使用LINQ降低代码复杂度

C# 使用LINQ降低代码复杂度,c#,performance,linq,C#,Performance,Linq,我有以下课程: public class Shipment { public int Id { get; set; } public List<Line> Lines { get; set; } } public class Line { public int Id { get; set; } public List<Package> Packages { get; set; } } public class Package { public int

我有以下课程:

public class Shipment
{
 public int Id { get; set; }  
 public List<Line> Lines { get; set; }
}

public class Line
{
 public int Id { get; set; }  
 public List<Package> Packages { get; set; }
}

public class Package
{
 public int Id { get; set; }  
 public List<Event> Events { get; set; }
}

public class Event 
{
 //irrelevant properties
}
公共类装运
{
公共int Id{get;set;}
公共列表行{get;set;}
}
公共班级线
{
公共int Id{get;set;}
公共列表包{get;set;}
}
公共类包
{
公共int Id{get;set;}
公共列表事件{get;set;}
}
公开课活动
{
//无关属性
}
我还有一本事件和PackageID字典:

Dictionary<Event, int> packageEvents; //already populated
字典包事件//已填充
我想将字典中的所有包事件与其对应的包进行匹配。我写的代码有3个重叠的foreach语句,因此O(n^3)的复杂性很高。我希望使用Linq将代码转换成更小的语句,并希望降低复杂性

foreach (var shipment in shipments)
{
    foreach (var line in shipment.Lines)
    {
        if (line.Packages.Any())
        {
            foreach (var package in line.Packages)
            {
                var eventsByPackage = packageEvents.Where(x => x.Value == package.Id).Select(x => x.Key);
                if (package.Events == null)
                {
                    package.Events = new List<Event>();
                }
                package.Events.AddRange(eventsByPackage);
            }
        }
    }
}
foreach(装运中的var装运)
{
foreach(装运中的var行。行)
{
if(line.Packages.Any())
{
foreach(行中的var包.Packages)
{
var eventsByPackage=packageEvents.Where(x=>x.Value==package.Id)。选择(x=>x.Key);
if(package.Events==null)
{
package.Events=新列表();
}
package.Events.AddRange(eventsByPackage);
}
}
}
}
如有任何建议,我将不胜感激。提前谢谢。

如果您想要Linq解决方案,我建议使用
选择many
两次,以获得展平
IEnumerable

var packages=装运
.SelectMany(发货=>shipping.line)
.SelectMany(line=>line.Packages);
foreach(包中的var包){
if(package.Events==null)
package.Events=新列表();
package.Events.AddRange(packageEvents
.Where(x=>x.Value==package.Id)
.选择(x=>x.Key));
}
然而,你必须扫描所有的包,这就是为什么你不能降低时间复杂度的原因;在Linq的帮助下,您所能获得的只是可读性

如果您想要Linq解决方案,我建议使用
SelectMany
两次,以获得展平
IEnumerable

var packages=装运
.SelectMany(发货=>shipping.line)
.SelectMany(line=>line.Packages);
foreach(包中的var包){
if(package.Events==null)
package.Events=新列表();
package.Events.AddRange(packageEvents
.Where(x=>x.Value==package.Id)
.选择(x=>x.Key));
}

然而,你必须扫描所有的包,这就是为什么你不能降低时间复杂度的原因;在Linq的帮助下,您所能获得的只是可读性

与Dmitry的答案相同,但语法略有不同

var merge = new Func<Package, Package>(package =>
{
    var found = packageEvents
        .Where(p => p.Value == package.Id)
        .Select(p => p.Key);

    if (package.Events == null)
        package.Events = new List<Event>();
    package.Events.AddRange(found);
    return package;
});

var query = from shipment in shipments
            from line in shipment.Lines
            from package in line.Packages
            select merge(package);
var merge=newfunc(包=>
{
var found=packageEvents
.Where(p=>p.Value==package.Id)
.选择(p=>p.Key);
if(package.Events==null)
package.Events=新列表();
package.Events.AddRange(已找到);
退货包装;
});
var query=来自装运中的装运
从装运中的第行开始
来自行中的包。包
选择合并(包);

与Dmitry的答案相同,但语法略有不同

var merge = new Func<Package, Package>(package =>
{
    var found = packageEvents
        .Where(p => p.Value == package.Id)
        .Select(p => p.Key);

    if (package.Events == null)
        package.Events = new List<Event>();
    package.Events.AddRange(found);
    return package;
});

var query = from shipment in shipments
            from line in shipment.Lines
            from package in line.Packages
            select merge(package);
var merge=newfunc(包=>
{
var found=packageEvents
.Where(p=>p.Value==package.Id)
.选择(p=>p.Key);
if(package.Events==null)
package.Events=新列表();
package.Events.AddRange(已找到);
退货包装;
});
var query=来自装运中的装运
从装运中的第行开始
来自行中的包。包
选择合并(包);

如果(line.Packages.Any())
是多余的,可以安全地删除。我认为站点更适合这个问题。3嵌套循环是
O(n^3)
的一个指示器(而
AddRange(eventsByPackage)
将使其成为
O(n^4)
),但是如果外部循环只是内部元素的分组,那么真正的复杂性仍然可以是
O(n)
,其中
n
是要处理的事件数。
if(line.Packages.Any())
是冗余的,可以安全地删除。我认为站点更适合这个问题。3个嵌套循环是
O(n^3)
(以及
AddRange(eventsByPackage)
将使其成为
O(n^4)
),但如果外部循环只是内部元素的分组,那么真正的复杂性仍然可以是
O(n)
,而
n
是要处理的事件数。奇怪的是,这被接受。此代码不起任何作用。
查询
只是一个定义。为了产生结果,它必须通过
foreach
ing或调用
ToList()
等方式执行,这很奇怪。很多人在尝试将LINQ用于非设计用途(本例中为更新)时都会失败。你是对的,这只是查询定义,与任何查询定义一样,它也需要像你提到的那样具体化,例如通过ToList,我只是没有在我的答案中包含显而易见的内容。查看gist以获得所提供解决方案的完整概述。奇怪的是,它被接受了。此代码不起任何作用。
查询
只是一个定义。为了产生结果,它必须通过
foreach
ing或调用
ToList()
等方式执行,这很奇怪。很多人在尝试将LINQ用于非设计用途(本例中为更新)时都会失败。你是对的,这只是查询定义,与任何查询定义一样,它也需要像你提到的那样具体化,例如通过ToList,我只是没有在我的答案中包含显而易见的内容。有关所提供解决方案的完整概述,请查看要点