使用LINQ降低代码复杂性

时间:2018-01-15 12:12:23

标签: 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 Id { get; set; }  
 public List<Event> Events { get; set; }
}

public class Event 
{
 //irrelevant properties
}

我还有一个事件字典和packageIds:

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);
            }
        }
    }
}

我将不胜感激任何建议。提前谢谢。

2 个答案:

答案 0 :(得分:4)

如果您需要 Linq 解决方案,建议您使用SelectMany 两次以获得展平IEnumerable<Package>

var packages = shipments
  .SelectMany(shipment => shipment.Lines)
  .SelectMany(line => line.Packages);

foreach(var package in packages) {
  if (package.Events == null)
    package.Events = new List<Event>();

  package.Events.AddRange(packageEvents
    .Where(x => x.Value == package.Id)
    .Select(x => x.Key));
}

但是,您必须扫描所有软件包,这就是无法减少 O(n**3)时间复杂度的原因;您在Linq的帮助下获得的所有内容都是可读性

答案 1 :(得分:2)

与德米特里的答案相同,但语法略有不同

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