在保留唯一属性的同时合并对象

时间:2017-07-05 23:17:56

标签: c# merge

我正在开发一个C#项目,该项目获取自定义类的数百个对象的列表,并将它们合并到一个新列表中。在某些情况下,单个实际项目在列表中会多次表示,但具有不同的属性。我正在寻找一种有效的方法将这两个列表合并在一起,以便任何时候在我的搜索键属性上找到重复,其他属性合并在一起(通过覆盖其中一个对象的属性或通过创建具有合并属性的新对象)而不是删除第二个实例。

以下是我想要做的一个例子: 类狗的对象与元素(ID,所有者,品种,颜色)。 Dog Rover由Sharon和Paul共同拥有。我希望我的合并列表包含文本“Sharon / Paul”作为“Owner”变量的新属性。

原始列表:

列表A:

1.Rover(23,Sharon,Labrador,Black)

2.Spot(40,Paul,Retriever,Golden)

列表B:

  1. Rover(23,Paul,Labrador,Black)
  2. 合并列表:

    1. Rover(23岁,Sharon / Paul,拉布拉多,黑人)

    2. Spot(40,Paul,Retriever,Golden)

    3. 我已经能够加入列表来创建: 1.罗孚(23岁,沙龙,拉布拉多,黑人) 2.罗孚(23岁,保罗,拉布拉多,黑人) 3.现货(40,Paul,Retriever,Golden) 或者在列表上运行.Unique来创建: 1.罗孚(23岁,沙龙,拉布拉多,黑人) 2.现场(40,保罗,猎犬,金)

      但是这些都没有给我最小的清单所需的所有信息。

2 个答案:

答案 0 :(得分:1)

鉴于您的列表定义如下:

var listA = new []
{
    new Dog() { ID  = 23, Owner = "Sharon", Breed = "Labrador", Colour = "Black" },
    new Dog() { ID  = 40, Owner = "Paul", Breed = "Retriever", Colour = "Golden" },
};

var listB = new []
{
    new Dog() { ID  = 23, Owner = "Paul", Breed = "Labrador", Colour = "Black" },
};

您的数据中有趣的是,Dog记录未规范化 - 您具有相同的ID具有不同的属性数据,即Owner可能不同。我认为确保最终查询还确保同时处理BreedColour属性中的多个值也很重要。

您需要的查询是:

var query =
    from dog in listA.Concat(listB)
    orderby dog.ID
    group dog by dog.ID into gdogs
    select new Dog()
    {
        ID = gdogs.Key,
        Owner = String.Join("/", gdogs.Select(x => x.Owner).Distinct()),
        Breed = String.Join("/", gdogs.Select(x => x.Breed).Distinct()),
        Colour = String.Join("/", gdogs.Select(x => x.Colour).Distinct()),
    };

如果您有多个列表,只需继续致电.Concat即可将它们连接在一起。

您从此查询中获得的结果是:

query

答案 1 :(得分:-1)

你需要的是一个全外连接来获得所有的狗,然后合并匹配的狗。在LINQ中完成外部连接,方法是执行左外连接,然后执行右反半连接,然后使用Union组合它们。

我假设每个狗ID最多只出现在每个列表中一次,而BreedColour会相同,如果不是,您可以像Owner那样合并它们。

var leftDogs = from da in dogsA
               join db in dogsB on da.ID equals db.ID into dbj
               from db in dbj.DefaultIfEmpty()
               select new Dog {
                   ID = da.ID,
                   Owner = (db == null ? da.Owner : $"{da.Owner}/{db.Owner}"),
                   Breed = da.Breed,
                   Colour = da.Colour
               };

var rightDogs = from db in dogsB
                where !dogsA.Any(da => da.ID == db.ID)
                select db;

var ans = leftDogs.Union(rightDogs);

如果多个所有者狗的每个列表中可能存在重复条目,您可以减少第一个列表然后减少组合:

public static IEnumerable<Dog> MergeDupDogs(IEnumerable<Dog> dogsA, IEnumerable<Dog> dogsB) {
    var dogsAReduced = dogsA.Aggregate(new Dictionary<int, Dog>(), (acc, da) => {
        if (!acc.ContainsKey(da.ID))
            acc.Add(da.ID, da);
        else
            acc[da.ID] = new Dog { ID = da.ID, Owner = $"{acc[da.ID].Owner}/{da.Owner}", Breed = da.Breed, Colour = da.Colour };
        return acc;
    });

    return dogsB.Aggregate(dogsAReduced, (acc, db) => {
        if (!acc.ContainsKey(db.ID))
            acc.Add(db.ID, db);
        else
            acc[db.ID] = new Dog { ID = db.ID, Owner = $"{acc[db.ID].Owner}/{db.Owner}", Breed = db.Breed, Colour = db.Colour };
        return acc;
    }).Select(e => e.Value);
}