简体   繁体   中英

c# How to select distinct items from objects using LINQ

I would like to select only the distinct usernames and id from the query. Currently, it is returning duplicates.

                  TotalUsers = (from p in reports
                                   group p by new
                                   {
                                       p.UserID,
                                       p.UserName
                                   } into grp
                                   select new Employee()
                                   {
                                       Name = grp.Key.UserName,
                                       Id = grp.Key.UserID
                                   }).ToList();

I tried doing Name = grp.Key.UserName.First().ToString() but this gives me the first letter of the username.

Current Output Example:

{UserID=1,UserName="N1"}
{UserID=2,UserName="N2"}
{UserID=1,UserName="N1"}
{UserID=2,UserName="N2"}

Desired Output:

 {UserID=1,UserName="N1"}
 {UserID=2,UserName="N2"}

This is really hard to answer without knowing what your reports objects look like, and having a Minimal Reproducible Example .

I'm making the assumption that UserID is a unique identifier for the user. And that the UserName will always correspond with the UserID . If so, the following should give you the distinct users...

TotalUsers = reports.GroupBy(x => x.UserID)
    .Select(x => x.First())
    .Select(x => new Employee()
                               {
                                   Name = x.UserName,
                                   Id = x.UserID
                               })
    .ToList();

The GroupBy will collate all of the items with the same UserID . Then we select the first of those items - this is entirely arbitrary, and without knowing why you are getting duplicates, this may not be the best solution - it may be worth looking into why you are getting duplicates, rather than solving the problem here . Then each of these is converted into an Employee object.

Let's assume your key (for users) is ID and that you have this DataSet:

Report
ID    |  UserID    |    UserName

1     |  1         |    UN1
2     |  2         |    UN2
3     |  3         |    UN1

Than, when you want distinct couples of (UserID, UserName) you will have the UserName UN1 twice, once for ID 1 and once for ID 3. The only way to go around it is to ignore the UserID. It means that you have to change to code in this way:

TotalUsers = (from p in reports
                               group p by new
                               {
                                   p.UserName
                               } into grp
                               select new Employee()
                               {
                                   Name = grp.Key.UserName
                               }).ToList();

Right Answer - EDIT AFTER EXAMPLES GIVEN

If that was not the case and your problem is that your query is returning twice the couple (1, UN1) from the following dataset:

Report
ID    |  UserID    |    UserName

1     |  1         |    UN1
2     |  2         |    UN2
3     |  3         |    UN1
4     |  1         |    UN1

it is not working because of a missing "Equals" method. You can solve it this way:

public class UserData{
     public string UserName {get;set;}
     public string UserId {get;set;}

     public override bool Equals(object x) {
        if (! (x is UserData)) return false;
        UserData y = (UserData) x;
        return this.UserName == x.UserName && this.UserId == x.UserId;
     }
}

TotalUsers = (from p in reports
                               group p by new UserData
                               {
                                   UserId = p.UserId,
                                   UserName = p.UserName
                               } into grp
                               select new Employee()
                               {
                                   Name = grp.Key.UserName,
                                   Id = grp.Key.UserId
                               }).ToList();

I'm creating group and its key contains $"{p.UserID}-{p.UserName}" and it will make sure its unique

TotalUsers = (from p in  new List<User>()
              group p by $"{p.UserID}-{p.UserName}"
                   into grp
              select new Employee()
              {
                  Name = grp.First().UserName,
                  Id = grp.First().UserID
              }).ToList();

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