2017-07-05 53 views
0

我正在处理一个C#项目,该项目需要自定义类的数百个对象的列表,并将它们合并到一个新列表中。在某些情况下,一个真实世界的项目可能会在列表中多次显示,但具有不同的属性。我正在寻找一种有效的方法来将这两个列表合并在一起,以便每次在我的搜索关键属性中找到重复项时,其他属性将合并在一起(通过覆盖其中一个对象的属性或创建一个具有合并属性的新对象),而不是删除第二个实例。在保留唯一属性的同时合并对象

下面是我想要做的一个例子: 带有元素(ID,所有者,品种,颜色)的Dog类的对象。狗路虎属于沙龙和保罗。我希望我的合并列表中包含文本“Sharon/Paul”作为“所有者”变量的新属性。

原有名单:

列表A:

1.Rover(23,沙龙,拉布拉多,黑色)

2.Spot(40,保罗,猎犬,金)

列表B:

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

合并列表:

  1. 罗孚(23,莎朗/保罗,拉布拉多,黑色)

  2. 点(40,保罗,猎犬,金)

我已经能够加入列表创建: 1.罗孚(23,沙龙,拉布拉多,黑色)01 2. Rover(23,Paul,Labrador,Black) 3. Spot(40,Paul,Retriever,Golden) 或者运行.Unique创建列表: 1. Rover(23,Sharon,Labrador,Black) 2. Spot(40,Paul,Retriever,Golden)

但是这些都没有给我所有我需要的信息在最小的列表中。

+1

分享你的代码,你写来解决上述问题 –

+0

是否有一个共同的基类?它是一个对象列表还是一个键/值对列表或某种地图或字典? – SledgeHammer

回答

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

如果有2个以上的所有者,该怎么办? – SledgeHammer

+0

正如答案中所述,我认为每个狗ID在每个列表中最多显示一次。原来的问题没有讨论两个以上所有者的可能性。 – NetMage

+0

@SledgeHammer我添加了一个选项来一起减少列表。 – NetMage

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不同合适ty数据,即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

+0

好使用'Concat' /'组''by'! – NetMage

相关问题