[英]Filter a hierarchical list using linq
這是我的產品型號
public class Product
{
public string Name{ get; set; }
public int ProductNumber{ get; set; }
public List<Product> ProductList { get; set; }
}
//// below is the structure of the list
IList<Product> rootList = new List<Product>
{
new Product
{
ProductNumber = 1, Name = "A",
ProductList = new List<Product> { new Product { ProductNumber = 2, Name = "A1",
ProductList = new List<Product> { new Product { ProductNumber = 3, Name = "A2", ProductList = new List<Product>()} }}
}
},
new Product
{
ProductNumber = 4, Name = "B",
ProductList = new List<Product> { new Product { ProductNumber = 5, Name = "B1",
ProductList = new List<Product> { new Product { ProductNumber = 6, Name = "B2", ProductList = new List<Product>()} }}
}
},
new Product
{
ProductNumber = 7, Name = "C",
ProductList = new List<Product> { new Product { ProductNumber = 8, Name = "C1",
ProductList = new List<Product> { new Product { ProductNumber = 9, Name = "C2", ProductList = new List<Product>()} }}
}
}
};
我需要過濾上面包含ProductNumber小於5的列表,即。 輸出預計是產品編號小於5的產品列表。
有沒有可用的擴展? 請幫忙。
這是我的預期結果
Product
{
ProductNumber : 1,
Name : "A",
ProductList : { {
ProductNumber : 2,
Name : "A1",
ProductList :{ {
ProductNumber = 3,
Name : "A2",
ProductList : null} }}
}
},
Product
{
ProductNumber : 4,
Name : "B"
ProductList : null
}
將“扁平 - 這棵樹”類似LINQ的功能拼湊起來相當容易
public static IEnumerable<T> Flatten<T>(
this IEnumerable<T> source,
Func<T, IEnumerable<T>> childSelector)
{
HashSet<T> added = new HashSet<T>();
Queue<T> queue = new Queue<T>();
foreach(T t in source)
if (added.Add(t))
queue.Enqueue(t);
while (queue.Count > 0)
{
T current = queue.Dequeue();
yield return current;
if (current != null)
{
IEnumerable<T> children = childSelector(current);
if (children != null)
foreach(T t in childSelector(current))
if (added.Add(t))
queue.Enqueue(t);
}
}
}
您可以在常規LINQ中使用它,例如
var lessThanFive = rootList
.Flatten(p => p.ProductList)
.Where(p => p.ProductNumber < 5)
.ToList();
編輯 :從你的編輯我可以看到這不是你想要的。 (你不想要一個產品列表,你想要一個產品樹......)我將把它留在這里,因為我非常喜歡它作為我認為你的問題的解決方案,但我會有想想你的新問題......
編輯 :如果您不介意修改原始對象,可以按如下方式使用:
rootList = rootList.Where(p => p.ProductNumber < 5).ToList();
foreach (var pr in rootList.Flatten(p => p.ProductList))
pr.ProductList = pr.ProductList.Where(p => p.ProductNumber < 5).ToList();
你需要這樣的東西:
public static class EnumerableExtensions
{
public static IEnumerable<TR> Recur<T, TR>(
this IEnumerable<T> source,
Func<T, bool> filter,
Func<T, IEnumerable<T>> recursor,
Func<T, IEnumerable<T>, TR> resultor)
{
foreach(var t in source)
if (filter(t))
yield return resultor(t, recursor(t));
}
}
你會這樣稱呼:
var q = rootList.Recur(
p => p.ProductNumber < 5,
p => p.ProductList,
(p, cs) => new
{
p.ProductNumber,
p.Name,
ProductList = cs
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.