Finding similar properties within a list of objects - c#

I have a class Employee:
public class Employee
{
public string SSN;
public string empNumber;
public int someValue;
}
I want to check if the employees share a similar SSN AND a similar empNumber. I have a List<Employee> available to search through. Employees cannot have the same SSN and empNumber. Ultimately, I want to populate a list that contains the employees that share only SSN and empNumber. If this list is not a size 0, then I know to send an error message.
I know I can use LINQ or a foreach, but I am not sure which would be best for this situation.

Seems like a pretty simple GroupBy - assuming your List<Employee> is in a variable employees:
var dupes = employees.GroupBy(e => new {e.SSN, e.empNumber})
.Where(g => g.Count() > 1);
The variable dupes will now contain an enumerable list of anonymous objects with the properties
SSN
empNumber
which will represent your duplicates. Each item is also itself an IEnumerable<Customer> containing the duplicates themselves (from the original list).

Related

How to query a list and return values where ID = any value in an array

I have 2 collections. 1 is an array of groupIds, and the other is an IEnumerable.
My user class contains another list of type IList, which denotes the groups the user belongs to:
public class User
{
public IList<Group> Groups { get; protected set; }
}
And the Group class looks something like this:
public class Group{
public long Group_Id { get; protected set; }
}
What I need to do is return a collection of all users who are in the groupIds array. I.e., I would want something like:
usersRepository.Where(user => user.Groups.Where(group => groupIds.Contains(group.id))
Such that if my groupIds array has group id of 5 and 6, all users in the useresRepository which belong to group 5 and 6 are returned.
So far, the best I've been able to come up with is the following:
UserRepo.Users.AsEnumerable().Where(user =>
user.GroupUsers.Where(wg => GroupIds.Contains(wg.Group_Id)));
But this is complaining since .Contains returns a boolean instead of my list, but I'm not sure how to fix that.
My code doesn't work due to .Contains() causing the expression to return a boolean rather than a collection. However, I'm not sure how else to check of the list of GroupIds nested within my User object contains the specified group ids.
Try Any .This will give you all the users that have any of the group mentioned in the groupIds array
UserRepo.Users.AsEnumerable().Where(user =>
user.Groups.Any(wg => GroupIds.Contains(wg.Group_Id)));
So you have a sequence of Users, where every User has a sequence of Groups, where every Group has a GroupId.
You also have a sequence of GroupIds.
IEnumerable <int> groupIds =
IQueryable<User> users = ...
You want all Users, that have at least one Group with a GroupId that is in you sequence of GroupIds.
Whenever you see "I want all items that have at least one ...", consider using Any:
var result = users
.Where(user => user.groups
.Select(group => group.groupId)
.Any(groupId => groupIds.Contains(groupId));
In words: from every user, take its collection of Groups. From every Group take the groupIds, and check if any of these groupIds is in collection groupIds. If so, keep this user in your result.
This can be a little bit shorter:
var result = users.Where(user => user.groups.Any(group => groupIds.Contains(group.groupId));

How to implement nested search in a list

I'm trying to solve a problem where I need to filter a list which hold my custom reference object. Search criteria is based on nested properties. For a reference guide, let consider Student and Subject classes.
public class Student
{
public String Name {get;set;}
public List<Subject> Subjects {get;set;}
}
public Subject
{
public String Name {get;set;}
}
Not only I want to search Student by their names but the same search should also work with subject names as well. I've a single field where the text can be entered. For student search by their names, I've done:
FilteredList = Students.Where(s => s.Name.Contains(searchQuery));
Now, I also want to search students by the subject names but only want to show the matching results. A student can take many courses but a query of "Chemistry" should only show students who are taking this course but the rest of the courses they're taking should be ignored.
Basically my FilteredList is bound with ListView and Subjects list should only contain matching results. I'm keeping original source aside as Students. Any help implementing this search is highly appreciated.
You could use the LINQ function Any in this case. Something like this should give you the indented results :
FilteredList = Students.Where(s => s.Subjects.Any(subs => subs.Name.Contains(subjectSearchQuery))
If you want to use both filters at the same time, you can chain
FilteredList = Students.Where(s => s.Name.Contains(searchQuery))
.Where(s => s.Subjects.Any(subs => subs.Name.Contains(subjectSearchQuery))
EDIT : Seems like I understood the question wrong, here is what I think is the right answer (see the comments on this answer)
In this you want to use Select, in a fashion like this :
FilteredList = Students.Where(s => s.Name.Contains(studentNameFilter))
.Select(s => new Student()
{
Name = s.Name,
subjects = s.Subjects.Where(sub => sub.Name.Contains(subjectNameFilter))
});
This should give you the results you want.

How to filter a list based on another list using Linq?

I have these two lists, one a list of Venue Objects, one a list of BlockedVenues objects.
I need to filter each item in the listOfAllVenues so that it doesn't contain any venue
that is blocked
IQueryable<Venue> listOfAllVenues = MyDB.Venues;
IQueryable<BlockedVenue> listOfBlockedVenues = Mydb.BlockedVenue;
//I need something to accomplish this please
// var listOfAllVenues_WithoutBlocked_Venues =
( Select All venues from listOfAllVenues
where listOfAllVenues.ID is NOT in
listOfBlockedVenues.VenueID)
Please note that yes both list types are different, but listOfAllVenues has an int ID field, and listOfBlockedVenues has a VenueID int field, i need to use these two
Many Thanks
Try this:
var filtered = listOfAllVenues
.Where(x=>!listOfBlockedVenues.Any(y=>y.VenueId == x.Id));
It will get all Venues where Id is not in blockedVenues list
As of NET 6, you can use ExceptBy.
var filtered = allVenues.ExceptBy(blockedVenues.Select(x => x.VenueID), venue => venue.ID);
This will get all venues except those whose ID is in blockedVenues.Select(x => x.VenueID)
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.exceptby?view=net-6.0

Linq Select All Items Matching Array

I have a data collection of type IEnumerable<Objects.LabourHours> containing labour records for various employees. I wish to filter the list and return only records for selected employees, which is specified by a list of int[] employees containing the EmployeeIDs.
class LabourHours
{
public int ID {get;set;}
public int EmployeeID {get;set;}
public int HoursWorked {get;set;}
}
How would I go about this? I am sure this has been asked before but I can't find anything similar on here. The closest I have found involves grouping the records by UserID, which is not what I need - I need the actual records.
You can filter your list with LINQ Where using Contains method:
var result = list.Where(x => employees.Contains(x.EmployeeID));
If you want the result to preserve the order of the employees array, you can use Select on the array. From the doc, it "Projects each element of a sequence into a new form", which is basically what you'd want to do in this case.
var result = employees.Select(e => labourHours.First(l => l.EmployeeID == e));
Use FirstOrDefault if all employees don't necessarily have an associated labourHours entry.

Distinct elements in LINQ

I have a situation where i display a list of products for a customer. So, there are two kinds of products. So, if customer is registerd to two products, then both the products get displayed. So, I need to display distinct rows. I did this:
var queryProducts = DbContext.CustomerProducts.Where(p => p.Customers_Id ==
customerID).ToList().Select(r => new
{
r.Id,
r.Products_Id,
ProductName = r.Product.Name,
ShortName = r.Product.ShortName,
Description = r.Product.Description,
IsActive = r.Product.IsActive
}).Distinct();
In this, customerID is the value that i get from dropdownlist. However, it still displays the same row twice. So, can you please let me know how i can display only distinct records.
The most likely reasons could be that Distinct when called with no parameter by default compares all the public properties for equality. I suspect your Id is going to be unique. Hence the Distinct is not working for you.
You can try something like
myCustomerList.GroupBy(product => product.Products_Id).Select(grp => grp.First());
I found this as answers to
How to get distinct instance from a list by Lambda or LINQ
Distinct() with lambda?
Have a look at LINQ Select Distinct with Anonymous Types
I'm guessing r.ID is varying between the two products that are the same, but you have the same Products_Id?
You can write an implementation of IEqualityComparer<CustomerProduct>. Once you've got that, then you can use this:
DbContext.CustomerProducts.Where(p => p.Customers_Id == customerId)
.ToList()
.Distinct(new MyComparer())
.Select(r => new {
// etc.
public class MyComparer : IEqualityComparer<CustomerProduct>
{
// implement **Equals** and **GetHashCode** here
}
Note, using this anonymous comparer might work better for you, but it compares all properties in the anonymous type, not just the customer ID as specified in the question.

Categories