c#和LINQ-根据对象分组对象,然后在其中查找公共值

时间:2015-04-20 03:59:40

标签: c# linq

我有一个对象集合,如下所示。

  List<Product> productList=new List<Product>();

产品的结构如下所示。

   public class Product
   {
       public  int Id;
       public Product(int id)
       {
          Id=id;

       }

       public List<SomeOtherList> t;
  }

班级产品包含其他一些列表

    public class SomeOtherList 
    {
        private int value;

        public  SomeOtherList(int val)
        {
            value=val;

       }


   }
        Product prodOne=new Product(1);
        List<SomeOtherList> temp_1=new List<SomeOtherList>();
        temp_1.Add(new SomeOtherList(10));
       temp_1.Add(new SomeOtherList(20));
       temp_1.Add(new SomeOtherList(30));
       prodOne.t=temp_1;

       Product prodTwo=new Product(2);
       List<SomeOtherList> temp_2=new List<SomeOtherList>();
       temp_2.Add(new SomeOtherList(100));
       temp_2.Add(new SomeOtherList(40));
       temp_2.Add(new SomeOtherList(30));
       prodTwo.t=temp_2;


       Product prodThree=new Product(1);
       List<SomeOtherList> temp_3=new List<SomeOtherList>();
       temp_3.Add(new SomeOtherList(10));
       temp_3.Add(new SomeOtherList(20));

       prodThree.t=temp_3;



      productList.Add(prodOne);
      productList.Add(prodTwo);
      productList.Add(prodThree);

我想得到&#34; SomeOtherList&#34;所有产品共有的对象。例如,对于产品ID 1,我应该将SomeOtherList对象20作为公共对象。

我编写了以下LINQ查询来实现此目的。

   List<Product> t=productList
                          .GroupBy(p => p.Id)
                          .Where(g => g.Count() == productList.Count)
                          .Select(x => x.First())
                          .ToList();

但它没有给我我想要的东西。有人可以指出该查询的错误吗?

3 个答案:

答案 0 :(得分:1)

当产品是某个特定值(即1)时,您SomeOtherList之间的 intersection

因此,您需要先选择具有正确Product的每个Id,然后将其SomeOtherList加在一起并按值分组。

要做到这一点,我们需要 flattern SomeOtherList的每个Product,我们可以使用SelectMany

  

将序列的每个元素投影到IEnumerable,并将生成的序列展平为一个序列。


Single Id

如果我们只对单个ID感兴趣,那么我们可以执行以下操作

var common1 = productList
    .Where(product => product.Id == 1)
    .SelectMany(product => product.t)
    .GroupBy(groupValue => groupValue.value)
    .Where(groupValue => groupValue.Count() > 1)
    .Select(values => values.First());

这将:

  1. 根据Id等于1
  2. 过滤产品
  3. 将每个产品SomeOtherList展平为一个IEnumerable
  4. 根据SomeOtherList.value
  5. 对每个元素进行分组
  6. 过滤掉任何只有1个条目的群组,因为我们只需要那些常见的

  7. 所有ID

    但是,如果我们想获得每个密钥的所有重复项列表,那么我们可以像单个Id那样执行相同的操作,但我们会根据ID对第一步进行分组。

    var common = productList
        .GroupBy(groupId => groupId.Id)
        .Select(groupId => groupId.SelectMany(product => product.t)
            .GroupBy(groupValue => groupValue.value)
            .Where(groupValue => groupValue.Count() > 1)
            .Select(values => values.First().value));
    

答案 1 :(得分:0)

在单个LINQ查询中很难做到,但是下面的代码应该可以工作。

var min = productList.Min(x=>x.Id);
var max = productList.Max(x=>x.Id);

for(int i = min; i<=max;i++)
{
    var products = productList.Where(x=>x.Id = i).ToList();
    List<SomeOtherList> cList = new List<SomeOtherList>();
    foreach(var product in products)
    {
        cList.AddRange(product.t);
    }
    var distinctList = cList.Distinct();
}

答案 2 :(得分:0)

由于嵌套列表,您需要在再次分组之前使用SelectMany对SomeOtherList列表进行分组。我认为这就是你所追求的目标。

var result = productList
    .GroupBy(p => p.Id)
    .Select(pg =>
        new
        {
            Id = pg.Key,
            CommonOtherList = pg
                .SelectMany(solg => solg.t)
                .GroupBy(solg => solg.value)
                .Where(solg => solg.Count() == pg.Count())
                .Select(solg => new { OtherId = solg.Key })
        });

foreach (var product in result)
{
    Console.WriteLine(product.Id);
    Console.WriteLine("**Common**");
    foreach (var otherProduct in product.CommonOtherList)
    {
        Console.WriteLine("-->{0}", otherProduct.OtherId);
    }
}