我正在开发一个C#项目,该项目获取自定义类的数百个对象的列表,并将它们合并到一个新列表中。在某些情况下,单个实际项目在列表中会多次表示,但具有不同的属性。我正在寻找一种有效的方法将这两个列表合并在一起,以便任何时候在我的搜索键属性上找到重复,其他属性合并在一起(通过覆盖其中一个对象的属性或通过创建具有合并属性的新对象)而不是删除第二个实例。
以下是我想要做的一个例子: 类狗的对象与元素(ID,所有者,品种,颜色)。 Dog Rover由Sharon和Paul共同拥有。我希望我的合并列表包含文本“Sharon / Paul”作为“Owner”变量的新属性。
原始列表:
列表A:
1.Rover(23,Sharon,Labrador,Black)
2.Spot(40,Paul,Retriever,Golden)
列表B:
合并列表:
Rover(23岁,Sharon / Paul,拉布拉多,黑人)
Spot(40,Paul,Retriever,Golden)
我已经能够加入列表来创建: 1.罗孚(23岁,沙龙,拉布拉多,黑人) 2.罗孚(23岁,保罗,拉布拉多,黑人) 3.现货(40,Paul,Retriever,Golden) 或者在列表上运行.Unique来创建: 1.罗孚(23岁,沙龙,拉布拉多,黑人) 2.现场(40,保罗,猎犬,金)
但是这些都没有给我最小的清单所需的所有信息。
答案 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
可能不同。我认为确保最终查询还确保同时处理Breed
和Colour
属性中的多个值也很重要。
您需要的查询是:
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
即可将它们连接在一起。
您从此查询中获得的结果是:
答案 1 :(得分:-1)
你需要的是一个全外连接来获得所有的狗,然后合并匹配的狗。在LINQ中完成外部连接,方法是执行左外连接,然后执行右反半连接,然后使用Union
组合它们。
我假设每个狗ID最多只出现在每个列表中一次,而Breed
和Colour
会相同,如果不是,您可以像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);
}