代码之家  ›  专栏  ›  技术社区  ›  Ty.

LINQ困境

  •  1
  • Ty.  · 技术社区  · 15 年前

    我无法有效地选择需要显示的信息。希望其他人对如何解决这个问题有更好的了解。

    考虑到以下数据结构,

    public class Department
    {
       public int ID { get; set; }
       public string Name { get; set; }
       public IList<Product> Products{ get; set; }
    }
    
    public class Product
    {
       public int ID { get; set; }
       public string Name { get; set; }
    }
    

    并给出以下数据

    Department1 = 
    {
        Id=1,
        Name="D1",
        Products = {new Product{Id=1, Name="Item1"}, new Product{Id=2, Name="Item2"}
    }
    
    Department2 = 
    {
        Id=2,
        Name="D2",
        Products = {new Product{Id=2, Name="Item2"}, new Product{Id=3, Name="Item3"}
    }
    

    如何选择“项2”是“d1”和“d2”的共同点?

    我尝试过使用交叉查询,但它似乎希望两个延迟的查询执行计划交叉,而不是两个IEnumerable列表或IList。

    对此,我们非常感谢您的帮助。

    编辑:看来我并不是很精确地试图保持简单。

    我有一个部门列表,每个部门都包含一个产品列表。鉴于这些列表,我如何根据特定标准选择其他产品列表。在本例中,我的标准是只选择存在于我所有部门中的产品。我只需要与所有元素相交的数据。

    7 回复  |  直到 15 年前
        1
  •  1
  •   bruno conde    15 年前

    我的 Intersect 功能正常:

            Department department1 = new Department
            {
                Id = 1,
                Name = "D1",
                Products = new List<Product> () { new Product { Id = 1, Name = "Item1" }, new Product { Id = 2, Name = "Item2" } }
            };
    
            Department department2 = new Department
            {
                Id = 2,
                Name = "D2",
                Products = new List<Product>() { new Product { Id = 2, Name = "Item2" }, new Product { Id = 3, Name = "Item3" } }
            };
    
            IEnumerable<Product> products = department1.Products.Intersect(department2.Products, new ProductComparer());
    
            foreach (var p in products)
            {
                Console.WriteLine(p.Name);
            }
    

    (编辑)

        public class ProductComparer : IEqualityComparer<Product>
        {
            public bool Equals(Product x, Product y)
            {
                return x.Name == y.Name && x.Id == y.Id;
            }
    
            public int GetHashCode(Product obj)
            {
                return obj.Id.GetHashCode() ^ obj.Name.GetHashCode();
            }
        }
    
        2
  •  1
  •   Lee    15 年前

    如果您想使用LINQ,那么您可以扁平化产品集合,并将每个集合与父部门对象相关联(这样您就有了一个(产品、部门)对的集合),然后重新组合产品。

    var sharedItems = new[] { department1, department2 }
                    .SelectMany(d => d.Products, (dep, prod) => new { Department = dep, Product = prod })
                    .GroupBy(v => v.Product)
                    .Where(group => group.Count() > 1);
    

    此查询的结果是一个对i组的枚举,其中键是产品,并且包含具有该产品的部门。

        3
  •  1
  •   Daniel Brückner    15 年前
    // Get a list of all departments.
    IEnumerable<Department> departments = GetAllDepartments();
    
    // Get a list of all products.
    var products = departments.SelectMany(d => d.Products).Distinct();
    
    // Filter out all products that are not contained in all departments.
    var filteredProducts = products.
        Where(p => departments.All(d => d.Products.Contains(p)));
    

    如果合并两个查询,将得到以下结果。

    var filteredProducts = departments.
        SelectMany(d => d.Products).
        Distinct().
        Where(p => departments.All(d => d.Products.Contains(p)));
    
        4
  •  0
  •   bytebender    15 年前

    也许我不完全理解这个问题,但这会奏效吗?

    var commonProducts = new List<Product>();
    
    Department1.Products.ForEach(delegate(Product product)
    {
        if (Department2.Products.Contains(product))
        {
            commonProducts.Add(product);
        }
    });
    
        5
  •  0
  •   Ruben Bartelink    15 年前

    使用selectmany生成产品/部门对的扁平列表(可能在匿名类中),然后使用group by按产品名称分组(并处理同一部门中同一产品的多个实例)。

    如果我以后有机会的话会扩大的。

        6
  •  0
  •   Amy B    15 年前

    将每个部门计划为 IEnumerable<Product> . 聚合产品列表-使用第一个列表作为起点,并在其余列表中相交。

    List<Product> commonProducts = departments
      .Select(d => d.Products.AsEnumerable() )
      .Aggregate( (soFar, nextList) => soFar
        .Intersect(nextList, productComparer) )
      .ToList()
    

    您必须实现一个ProductComparer来绕过引用相等性——如果产品是一个结构,则不必这样做。

        7
  •  -1
  •   Jason    15 年前

    LINQ查询语法更适合这些类型的查询:

    var q = from p1 in Department1.Products
            join p2 in Department2.Products
            on p1.Id equals p2.Id
            select p1;
    
    foreach (Product p in q) Console.WriteLine(p.Name);