C # and LINQ-group based on their IDs and then find common values ​​in them

I have a collection of objects like the following.

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

      

The structure of the Product class looks like this.

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

       }

       public List<SomeOtherList> t;
  }

      

Class Product contains a different list

    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);

      

I want to get "SomeOtherList" objects common to all products. For example, for Product ID 1, I should get a SomeOtherList 20 object as normal.

For this I wrote the following LINQ query.

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

      

But that doesn't give me what I want. Can someone point out what is wrong with this request?

+3


source to share


3 answers


You want intersection between yours SomeOtherList

when the product has a specific value (i.e. 1).

So, you need to first select each Product

one that has the correct Id

one and then combine them SomeOtherList

together and group by value.

To do this, we need to flatten each SomeOtherList

for a Product

, which we can do withSelectMany

Projects each element of a sequence to an IEnumerable and aligns the resulting sequences into a single sequence.


Single identifier

If we are only interested in one Id, we can do the following



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());

      

It will be:

  • Filter products based on Id equal to 1
  • Align each product SomeOtherList

    into one IEnumerable
  • Group each element based on SomeOtherList.value

  • Filter out the groups that only have 1 entry as we only want the ones that are general.

All identifiers

If, however, we would like to get a list of all the duplicates for each key, then we can do the same as for a single identifier, but we have the first step in which we group based on the identifier.

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


source


Difficult to do in one LINQ query, but the following code should work.



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();
}

      

0


source


Because of nested lists, you need to group the expanding of the SomeOtherList with SelectMany before grouping. I think this is what you need.

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);
    }
}

      

0


source







All Articles