tags:

views:

1640

answers:

7

Hello,

My object is "MyClass" with 2 properties : Id (int) and HourBy (int)

I have two list :

var List1 = new List<MyClass>();
var List2 = new List<MyClass>();

I'd like to get one list with : - Object from List1 present in List2 based on Id with Hourby (list2) < Hourby in List1 - Object from List1 no present in List2

//#Sample1
//List1 :
List1.add(new MyClass(1,10));
List1.add(new MyClass(2,20));
List1.add(new MyClass(3,30));
//List2 :
List2.add(new MyClass(1,10)); 
List2.add(new MyClass(2,15));
//I'd like to get :
new MyClass(2,5);
new MyClass(3,30);

//Sample2
List1 :
List1.add(new MyClass(1,10));
List1.add(new MyClass(2,20));
List1.add(new MyClass(3,30));
//List2 :
List2.add(new MyClass(1,10)); 
List2.add(new MyClass(2,15));
List2.add(new MyClass(2,2));
//I'd like to get :
new MyClass(2,3);
new MyClass(3,30);

Thanks,

+1  A: 

Hi!

You can do this by the following Linq statement:

var result = List1.Where(x => !List2.Select(y => y.Id).Contains(x.Id)
    || List2.Single(y => x.Id == y.Id).HourBy < x.HourBy);

Best Regards

Oliver Hanappi
Hey Oliver, I created my linq query in my project according to your example It was helped to me. Thanks
fyasar
+1  A: 

I think this is what you're after, based on the example lists you supplied...

var list3 = new List<MyClass>();

foreach(var item in list1)
{
   var totalFromOther = list2.Where(x => x.id == item.id).Sum(y => y.HourBy);
   var newItem = new MyClass() { id = item.Id, HourBy = item.HourBy - totalFromOther };
   if(newItem.HourBy > 0)
     list3.Add(newItem);
}
Kirschstein
A: 

The following code should do the trick:

public List<MyClass> MyExtractionMethod(List<MyClass> List1, List<MyClass> List2)
{
    var results = new List<MyClass>();

    // add all the items in List1 that are not in List2
    results.AddRange(List1.Where(x => !List2.Select(y => y.Id).Contains(x.Id)));

    foreach (var item in List2)
    {
        var sum1 = List1.Where(c => c.Id == item.Id).Sum(y => y.HoursBy);
        var sum2 = List2.Where(c => c.Id == item.Id).Sum(y => y.HoursBy);

        // check for uneven sums and only add the item if it hasn't already been added
        if (sum1 != sum2 && !results.Select(x => x.Id).Contains(item.Id))
        {
            // do not overwrite the existing item in the list, create a new object
            results.Add(new MyClass(item.Id, sum1 - sum2));
        }
    }

    return results;
}
James
A: 
var agg1 = from l in list1
           group l by l.ID into g
           select new { g.Key, Sum = g.Sum(_ => _.HourBy) };
var agg2 = from l in list2
           group l by l.ID into g
           select new { g.Key, Sum = g.Sum(_ => _.HourBy) };

var q = from l1 in agg1
        let l2 = agg2.FirstOrDefault(_ => _.Key == l1.Key)
        let sum = l1.Sum - (l2 != null ? l2.Sum : 0)
        where sum != 0
        select new MyClass(l1.Key, sum);

var list3 = q.ToList();
Lloyd
I'm not overly familiar with the 'let' clause. Is it evaluated once for the query, or once per row in this case?
MattH
+1  A: 

Here's a solution:

        var qry = from ee in
                       (from e1 in list1
                        join e2 in list2 on e1.Id equals e2.Id into gj
                        from e in gj.DefaultIfEmpty()
                        select new { 
                            e1.Id,
                            MainHourBy = e1.HourBy,
                            SecondHourBy = (e == null ? 0 : e.HourBy)
                        })
                   where ee.SecondHourBy < ee.MainHourBy
                   group ee by ee.Id into g
                   select new MyClass
                   {
                       Id = g.Key,
                       HourBy = g.First().MainHourBy - g.Sum(el => el.SecondHourBy)
                   };
bruno conde
A: 
//Group list 2, so there is one entry per ID, with HourBy = total hour by
var summedL2 = from item2 in List2
              group item2 by item2.ID into g
              select new Test(g.Key, g.Sum(item => item.HourBy));

var result = 
            //Select items from list1
             from item1 in List1
             //Left join to our summed List2
             join item2s in summedL2 on item1.ID equals item2s.ID into tempItem2s
             from item2 in tempItem2s.DefaultIfEmpty()
             //Where there is no match, or item2 is < item1
             where (item2 == null || item2.HourBy < item1.HourBy)
             //Select a new Test object, with the HourBy changed
             select new Test(item1.ID, item1.HourBy - (item2 == null ? 0 : item2.HourBy));
MattH
+1  A: 

I use this code, it's not perfect but working and may be clearer for newbie in Linq (like me)

List< MyClass> listRes = new List< MyClass>();
foreach ( MyClass item in list1)
{
    var exist = list2
     .Select(x => x.MyClass)
     .Contains(item);

    if (!exist)
     listRes.Add(item);
    else
    {
     var totalFromOther = list2
      .Where(x => x.MyClass.Id == item.Id)
      .Sum(y => y.HourBy);

     if (item.HourBy != totalFromOther)
     {        
      item.HourBy = item.HourBy - totalFromOther;
      listRes.Add(item);
     }            
    }   
}

Thanks for you help,

Kris-I