2

I have one list which has data and sometimes it contains duplicate rows and I want to remove that duplicate row for that I used below code

num = numDetailsTemp.Distinct().ToList();
var query = num.GroupBy(o => new { o.Number })
                                  .Select(group =>
                                        new
                                        {
                                            Name = group.Key,
                                            Numbers = group.OrderByDescending(x => x.Date)
                                        })
                                  .OrderBy(group => group.Numbers.First().Date);
                            List<NumberDetails> numTemp = new List<NumberDetails>();

                            foreach (var group in query)
                            {
                                foreach (var numb in group.Numbers)
                                {
                                    numTemp.Add(numb);
                                    break;
                                }
                            }
                            num = numTemp;

The below image shows the duplicate value from the list.

enter image description here

And when I apply remove duplicate it give me an output

enter image description here

But I want to remove that row which not contains alter no or id proof and date like shown in first image first row not, contains AlterNo and ID Proof and date and the second row contains that so I want to remove the first row and display only second row. The date is compulsory to check and after that AlterNo and ID Proof.

Community
  • 1
  • 1
user10753256
  • 141
  • 7

3 Answers3

2

You can try the following:

var group = 
    list
    .GroupBy(r => r.Number)
    .SelectMany(g => g) //flatten your grouping and filter where you have alterno and id
    .Where(r => !string.IsNullOrEmpty(r.AlterNo) && !string.IsNullOrEmpty(r.Id))
    .OrderByDescending(r=>r.Date)
    .ToList();
JohanP
  • 5,252
  • 2
  • 24
  • 34
  • I want date also because main is date then alteno and id proof – user10753256 May 25 '19 at 04:42
  • Your question does not specify that as well as the image you posted. Update your question to make it clearer. – JohanP May 25 '19 at 04:45
  • Your image shows that both rows have dates. What exactly do you want? Must all 3 fields be present to be chosen? – JohanP May 25 '19 at 04:58
  • Yes I am comparing date because I want a recent date and not the previous date that if duplicate records have the same date then compare ID proof and AlterNo and remove those which not contains ID Proof and Alterno – user10753256 May 25 '19 at 05:01
1

You may eliminate duplicates using Distinct operator. First you need to define a comparer class which implements IEqualityComparer interface, and then pass it to the distinct operator in your method.

internal class NumberDetailsComparer : IEqualityComparer<NumberDetails>
{
    public bool Equals(NumberDetails x, NumberDetails y)
    {
        if (\* Set of conditions for equality matching *\)
        {
            return true;
        }
        return false;
    }

    public int GetHashCode(Student obj)
    {
        return obj.Name.GetHashCode(); // Name or whatever unique property
    }
} 

And here is how to use it:

var distinctRecords = source.Distinct(new NumberDetailsComparer());

All you need to do is define the criteria for comparer class. Hope this solves your problem.

This link could be useful for a fully working example:

http://dotnetpattern.com/linq-distinct-operator

Siavash Rostami
  • 1,883
  • 4
  • 17
  • 31
0

So you have a sequence of NumberDetails, and a definition about when you would consider to NumberDetails equal.

Once you have found which NumberDetails are equal, you want to eliminate the duplicates, except one: a duplicate that has values for AlterNo and IdProof.

Alas you didn't specify what you want if there are no duplicates with values for AlterNo and IdProof. Nor what you want if there are several duplicates with values for AlterNo and IdProof.

But let's assume that if there are several of these items, you don't care: just pick one, because they are duplicates anyway.

In your requirement you speak about duplicates. So let's write a class that implements your requirements of equality:

class NumberDetailEqualityComparer : IEqualityComparer<NumberDetail>
{
    public static IEQualityComparer<NumberDetail> Default {get;} = new NumberDetaulEqualityComparer();

    public bool Equals(NumberDetail x, NumberDetail y)
    {
         if (x == null) return y == null;              // true if both null
         if (y == null) return false;                  // because x not null and y null
         if (Object.ReferenceEquals(x, y) return true; // because same object
         if (x.GetType() != y.GetType()) return false; // because not same type

         // by now we are out of quick checks, we need a value check
         return x.Number == y.Number
             && x.FullName == y.FullName
             && ...
             // etc, such that this returns true if according your definition
             // x and y are equal
    }

You also need to implement GetHashCode. You can return anything you want, as long as you are certain that if x and y are equal, then they return the same HashCode Furthermore it would be more efficient that if x and y not equal, then there is a high probability for different HashCode.

Something like:

public int GetHashCode(NumberDetail numberDetail)
{
    const int prime1 = 12654365;
    const int prime2 = 54655549;

    if (numberDetail == null) return prime1;

    int hash = prime1;
    unsafe
    {
        hash = prime2 * hash + numberDetail.Number.GetHashCode();
        hash = prime2 * hash + numberDetail.FullName.GetHashCode();
        hash = prime2 * hash + numberDetail.Date.GetHashCode();
        ...
    }
    return hash;

Of course you have to check if any of the properties equal NULL before asking the HashCode.

Obviously in your equality (and thus in GetHashCode) you don't look at AlterNo nor IdProof.

Once that you've defined precisely when you consider two NumberDetails equal, you can make groups of equal NumberDetails

var groupsEqualNumberDetails = numberDetails.GroupBy(

    // keySelector: make groups with equal NumberDetails:
    numberDetail => numberDetail,

    // ResultSelector: take the key and all NumberDetails thas equal this key:
    // and keep the first one that has values for AlterNo and IdProof
    (key, numberDetailsEqualToKey) => numberDetailsEqualToKey
          .Where(numberDetail => numberDetail.AlterNo != null
                              && numberDetail.IdProof != null)
          .FirstOrDefault(),

    // KeyComparer: when do you consider two NumberDetails equal?
    NumberDetailEqualityComparer.Default;
}
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116