有没有办法使用LINQ合并重复项目的集合及其子集合?

时间:2014-08-20 03:47:45

标签: c# linq

示例类:

public class Pallet
{
    public int Id { get; set; }
    public List<Location> Locations { get; set; }
}

public class Location
{
    public int Id { get; set; }
}

鉴于此输入:

var input = new List<Pallet>
{
    new Pallet
    {
        Id = 1,
        Locations = new List<Location>
        {
            new Location { Id = 1 },
            new Location { Id = 3 }
        }
    },
    new Pallet
    {
        Id = 2,
        Locations = new List<Location>
        {
            new Location { Id = 2 }
        }
    },
    new Pallet
    {
        Id = 1,
        Locations = new List<Location>
        {
            new Location { Id = 1 },
            new Location { Id = 4 }
        }
    },
};

是否有一种很好的LINQ方法可以将重复项(在父集合和子集合中)折叠到相当于此的位置?

var output = new List<Pallet>
{
    new Pallet
    {
        Id = 1,
        Locations = new List<Location>
        {
            new Location { Id = 1 },
            new Location { Id = 3 },
            new Location { Id = 4 }
        }
    },
    new Pallet
    {
        Id = 2,
        Locations = new List<Location>
        {
            new Location { Id = 2 }
        }
    }
};

debugger

是的,我可以迭代收集并手动合并项目,但我很好奇LINQ会/可以提供更具表现力的东西。

2 个答案:

答案 0 :(得分:3)

您可以使用GroupBy收集匹配的ID,然后使用Select创建新的收藏集:

var output = input.GroupBy(pallet => pallet.Id)
    .Select(grp => new Pallet {
        Id = grp.Key,
        Locations = grp.SelectMany(pallet => pallet.Locations).Distinct().ToList()
    }).ToList();

上面提到的一点是,Distinct()只能在课程类型上正常工作,如果你要么提供IEqualityComparer<Location>,要么拥有&#34;位置&#34;类实现IEquatable<Location>(并覆盖object.GetHashCode):

public class Location : IEquatable<Location>
{
    public int Id { get; set; }

    public bool Equals(Location other)
    {
        //Check whether the compared object is null.  
        if (object.ReferenceEquals(other, null)) return false;

        //Check whether the compared object references the same data.  
        if (object.ReferenceEquals(this, other)) return true;

        return Id == other.Id;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

或者,您可以在选择每个组中的第一个位置时使用第二个GroupBy代替所有爵士乐:

var output = input.GroupBy(pallet => pallet.Id)
    .Select(grp => new Pallet {
        Id = grp.Key,
        Locations = grp.SelectMany(pallet => pallet.Locations)
            .GroupBy(location => location.Id)
            .Select(location => location.First())
            .ToList()
    }).ToList();

答案 1 :(得分:2)

这个足够好吗?

var output = from p in input
             group p by p.Id into g
             select new Pallet
             {
                 Id = g.Key,
                 Locations = (from l in g.SelectMany(x => x.Locations)
                              group l by l.Id into gl
                              select new Location { Id = gl.Key }).ToList()
             };