简体   繁体   中英

Using LINQ Distinct in C#

I have an issue using distinct in LINQ. I have this list:

LineIdChanged   LineId  OldGatewayPCId  NewGatewayPCId  LineStringID    PlantID
1               93      83              88              160             2
2               93      83              88              161             2
3               94      82              87              162             2
4               94      82              87              163             2

What I have tried is to get a distinct LineId value, so in this case I should only get two objects instead of all four objects. I have tried this:

  var s = (from n in _dataBaseProvider.SelectPjdGatewayLineChanged(selectedSourcePlant.LPS_Database_ID)
          select new PjdGatewayLineChanged() { LineId = n.LineId, LpsLineNo = n.LpsLineNo, LineIdChanged = n.LineIdChanged}).Distinct();

  LinesOld = s.ToList();

But this gives me all 4 objects.

You need to use MoreLINQ's DistinctBy :

var s = 
    (from n in _dataBaseProvider.SelectPjdGatewayLineChanged
    (selectedSourcePlant.LPS_Database_ID)
    select new PjdGatewayLineChanged
    { 
        LineId = n.LineId,
        LpsLineNo = n.LpsLineNo, 
        LineIdChanged = n.LineIdChanged
    })
    .DistinctBy(p => p.LineId);

what your problem is that the LINQ and the .Net framework dosent know how to differentiate betwwen different objects of type PjdGatewayLineChanged . so it uses the default thing which is to look for equality in the terms of memory reference.

So what you need to do instead is use the second overload of this method and provide an IEqualityComparer

see here

Distinct<TSource>(IEnumerable<TSource>, IEqualityComparer<TSource>)

so that LINQ known how to compare diff instances of type PjdGatewayLineChanged
msdn link of IEqualityComparer

If you consider all the rows to be equal if they have some fields equal:

var s = (from p in _dataBaseProvider.SelectPjdGatewayLineChanged(selectedSourcePlant.LPS_Database_ID)
    select new PjdGatewayLineChanged() 
    { 
        LineId = p.LineId,
        LpsLineNo = p.LpsLineNo, 
        LineIdChanged = p.LineIdChanged
    })
    .GroupBy(p => p.LineId)
    .Select(p => p.First());

You group-by by your id and then for each group take the first row.

or, more compact,

var s = from p in _dataBaseProvider.SelectPjdGatewayLineChanged(selectedSourcePlant.LPS_Database_ID)
    group p by p.LineId into q
    let r = q.First()
    select new PjdGatewayLineChanged() 
    { 
        LineId = r.LineId,
        LpsLineNo = r.LpsLineNo, 
        LineIdChanged = r.LineIdChanged
    };

In this way the creation of PjdGatewayLineChanged has been moved to the last step (after the selection of the right "candidate" of the groupby.

Here is the thing. The Distinct(IEnumerable) method returns an unordered sequence that contains no duplicate values. It uses the default equality comparer, Default , to compare values.

There are two options to use .Distinct() with your custom types:

  1. provide your own GetHashCode and Equals methods for the PjdGatewayLineChanged .
  2. use overloaded Distinct with your custom Equality Comparer

For more info check MSDN for Distinct check MSDN for Distinct, you'll find good documentation code snippets which will help you implement needed functionality.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM