2

How can I convert the below loop into simple linq code. The program is filtering out duplicate records.You can see the combination of SyID and PtID is repeating in the list, Those records should have only one entry in filtered list.First we need group the items by SyID then get distinct PtID from the list.

    public class ConnectionDetail
{
    public long SyID { get; set; }

    public long PtID { get; set; }

    public double Usage { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var details = new List<ConnectionDetail>();
        details.Add(new ConnectionDetail() { SyID = 1, PtID = 1, Usage = 1500 });
        details.Add(new ConnectionDetail() { SyID = 1, PtID = 1, Usage = 1500 });
        details.Add(new ConnectionDetail() { SyID = 1, PtID = 2, Usage = 560 });
        details.Add(new ConnectionDetail() { SyID = 1, PtID = 3, Usage = 850 });
        details.Add(new ConnectionDetail() { SyID = 1, PtID = 4, Usage = 1222 });
        details.Add(new ConnectionDetail() { SyID = 1, PtID = 5, Usage = 2000 });
        details.Add(new ConnectionDetail() { SyID = 1, PtID = 5, Usage = 2000 });

        details.Add(new ConnectionDetail() { SyID = 2, PtID = 1, Usage = 1500 });
        details.Add(new ConnectionDetail() { SyID = 2, PtID = 2, Usage = 1300 });
        details.Add(new ConnectionDetail() { SyID = 2, PtID = 3, Usage = 560 });
        details.Add(new ConnectionDetail() { SyID = 2, PtID = 3, Usage = 560 });
        details.Add(new ConnectionDetail() { SyID = 2, PtID = 4, Usage = 1580 });
        details.Add(new ConnectionDetail() { SyID = 2, PtID = 4, Usage = 1580 });
        details.Add(new ConnectionDetail() { SyID = 2, PtID = 5, Usage = 4000 });

        var distinctSet = new List<ConnectionDetail>();
        foreach (var detail in details)
        {
            if (!distinctSet.Any(x => x.SyID == detail.SyID && x.PtID == detail.PtID))
            {
                distinctSet.Add(new ConnectionDetail() { SyID = detail.SyID, PtID = detail.PtID, Usage = detail.Usage });
            }
        }
        Console.ReadKey();
    }
Mc27
  • 47
  • 5
  • You can use `.Distinct()`. This will return a IEnumerable with distinct values. You'll have to override `.Equals()` and `.GetHashCode()` for your classes though. –  Dec 05 '16 at 08:47
  • Possible duplicate of [Distinct by property of class by linq](http://stackoverflow.com/questions/2537823/distinct-by-property-of-class-by-linq) – haim770 Dec 05 '16 at 08:47
  • Why `Usage` is of type `double`, not `int` (or `long`)? – Dmitry Bychenko Dec 05 '16 at 08:49
  • There will be decimal values. @haim770 this is not duplicate, You need group the first by SyID then get first PtID from the list. – Mc27 Dec 05 '16 at 08:54
  • The method is not the same, but the result should be the same. If the list is not too large then grouping is fast enough, and the code is smaller. – Dialecticus Dec 05 '16 at 09:01
  • The method in the post mentioned by haim770 can also be used with multiple properties by using *new{propA,propB}*: `distinctSet = (from detail in details group detail by new {detail.SyID,detail.PtID} into g select g.First()).ToList();` – Me.Name Dec 05 '16 at 09:09

1 Answers1

6

Use EqualityCompare:

public class ConnectionDetailEqualityComparer : IEqualityComparer<ConnectionDetail>
{
    public bool Equals(ConnectionDetail x, ConnectionDetail y)
    {
        return x.SyID == y.SyID && x.PtID == y.PtID && x.Usage == y.Usage;
    }

    public int GetHashCode(ConnectionDetail obj)
    {
        return obj.SyID.GetHashCode() ^ obj.PtID.GetHashCode() ^ obj.Usage.GetHashCode();
    }
}

With it you could distinct your collection:

var distinctSet = details.Distinct(new ConnectionDetailEqualityComparer());
Maksim Simkin
  • 9,561
  • 4
  • 36
  • 49