(完整代码:https://dotnetfiddle.net/tdKNgH)
我有两个由ParentName
关联的列表,我想以特定的方式加入它们。
class Parent
{
public string ParentName { get; set; }
public IEnumerable<string> ChildNames { get; set; }
}
class Child
{
public string ParentName { get; set; }
public string ChildName { get; set; }
}
var parents = new List<Parent>()
{
new Parent() {ParentName = "Lee"},
new Parent() {ParentName = "Bob"},
new Parent() {ParentName = "Tom"}
};
var children = new List<Child>()
{
new Child() {ParentName = "Lee", ChildName = "A"},
new Child() {ParentName = "Tom", ChildName = "B"},
new Child() {ParentName = "Tom", ChildName = "C"}
};
我正在使用foreach循环加入,并且它有效,但有更简洁的方法吗?
foreach (var parent in parents)
{
var p = parent; // to avoid foreach closure side-effects
p.ChildNames = children.Where(c => c.ParentName == p.ParentName)
.Select(c => c.ChildName);
}
以下是生成的父母列表的样子:
Parent Children
------ --------
Lee A
Bob (empty)
Tom B,C
答案 0 :(得分:1)
您可以为枚举添加扩展方法:
public static void Each<T>(this IEnumerable<T> source, Action<T> action)
{
if (action == null)
return;
foreach (T obj in source)
action(obj);
}
然后做:
parents.Each(p => p.ChildNames = children.Where(c => c.ParentName == p.ParentName)
.Select(c => c.ChildName));
答案 1 :(得分:1)
您可以进行群组加入。但LINQ并不打算更新。所以我不确定这是否会让你真正有用。
IEnumerable<Parent> parents = ...;
var parentsWithChildren = parents.GroupJoin(children,
c => c.ParentName,
c => c.ParentName,
(a, b) => new
{
Parent = a,
ChildNames = b.Select(x => x.ChildName)
});
foreach (var v in parentsWithChildren)
{
v.Parent.ChildNames = v.ChildNames;
}
如果给你的所有人都是父名称和孩子,而不是完整的Parent
对象,那肯定会有所帮助,因为那样你就可以将这个集合加入到子名中,并且创建父项的实例,我创建一个匿名类型((a, b) => new { ... }
)。但是,因为我假设您的Parent
对象实际上不仅仅包含一个名称而且这只是一个例子,这似乎是您最好的选择。
答案 2 :(得分:1)
考虑将父母的姓名称为Parent.Name
而不是Parent.ParentName
(父母的父母?),Child
有同样的问题......
class Parent
{
public string Name { get; set; }
public IEnumerable<string> ChildrenNames { get; set; }
}
class Child
{
public string ParentName { get; set; }
public string Name { get; set; }
}
您可以先通过创建foreach
数组完全避免parentNames
:
var parentNames = new[] { "Lee", "Bob", "Tom" };
var allChildren = new List<Child>()
{
new Child() {ParentName = "Lee", Name = "A"},
new Child() {ParentName = "Tom", Name = "B"},
new Child() {ParentName = "Tom", Name = "C"}
};
这样父母完全由LINQ构建而没有任何副作用(没有更新任何变量),它应该非常简单:
var parents =
from parentName in parentNames
join child in allChildren on parentName equals child.ParentName into children
select new Parent { Name = parentName, ChildrenNames = children.Select(c => c.Name) };
答案 3 :(得分:1)
鉴于LINQ基于功能原则,副作用通常是一个很大的禁忌(也是为什么没有foreach
方法的原因)。
因此,我建议采用以下解决方案:
var parents = new List<Parent>()
{
new Parent() { ParentName = "Lee" },
new Parent() { ParentName = "Bob" },
new Parent() { ParentName = "Tom" }
};
var children = new List<Child>()
{
new Child() { ParentName = "Lee", ChildName = "A" },
new Child() { ParentName = "Tom", ChildName = "B" },
new Child() { ParentName = "Tom", ChildName = "C" }
};
var parentsWithChildren = parents.Select(x => new Parent
{
ParentName = x.ParentName,
ChildNames = children
.Where(c => c.ParentName == x.ParentName)
.Select(c => c.ChildName)
});
foreach (var parent in parentsWithChildren)
{
var childNamesConcentrated = string.Join(",", parent.ChildNames);
var childNames = string.IsNullOrWhiteSpace(childNamesConcentrated)
? "(empty)" : childNamesConcentrated;
Console.WriteLine("Parent = {0}, Children = {1}", parent.ParentName, childNames);
}
上述解决方案,通过设置Parent
,不修改集合parents
的{{1}}个对象。相反,它会创建一组新的ChildNames
s及其各自的ChildNames。
答案 4 :(得分:1)
您可以使用ToLookup获得最佳性能并减少内存损失:
var clu = children.ToLookup(x => x.ParentName, x => x.ChildName);
parents.ForEach(p => p.ChildNames = clu[p.ParentName]);