Pulling objects from a collection that satisfies a condition - c#

I was wondering whether you know using LINQ in C# to pull a list of objects from a collection that satisfies a condition?
I am trying to pull a list of Person objects from a list whose IDs match in an integer list. Please see the code below (I am trying to pull all person objects whose IDs are in the integer list).
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
...
var intList = new List<int>() { 1, 2, 3, 4 };
var perList = new List<Person>
{
new Person {Id = 1, FirstName = "Thomas", LastName = "Joseph"},
new Person {Id = 2, FirstName = "Joseph", LastName = "Austin"},
new Person {Id = 3, FirstName = "Lee", LastName = "Hentry"},
new Person {Id = 4, FirstName = "Abraham", LastName = "Tony"}
};

You can use the Where and Contains methods:
var people = perList
.Where(person => intList.Contains(person.Id))
.ToList();

You can use the Where and Any methods:
var filteredPeople = perList.Where(person => intList.Any(person.Id)).ToList();

Related

How to merge two lists of objects based on a property?

I have the two lists below where one comes from the database and the other from a JSON. The one from the database has it's Id associated.
List from database:
EmployeeId FirstName LastName EmployeeNumber
1234 Tom Cruise 98372829
5555 James Bond 93932228
The employeeId is a GUID Saved in the database.
Now I retrieve a list of Employees again to detect changes - James Bond Lastname changed. And I used automapper to map in the same format as my database entity.
List from JSON:
EmployeeId FirstName LastName EmployeeNumber
000-0000... Tom Cruise 98372829
000-0000... James Carter 93932228
Now I want to update the first list with the FirstName and LastName based on the EmployeeNumber.
// Employees retrieved in JSON
var retrievedEmployees = JsonSerializer.Deserialize<List<EmployeeDto>>(methodToRetrieveEmployees()))!.ToList();
var mappedEmployees = _mapper.Map<IEnumerable<Employee>>(retrievedEmployees);
var existingEmployeeFromDatabase = await GetExistingEmployees();
var employeesWithLatestUpdates = mappedEmployees
.Where(y => existingEmployeeFromDatabase.Any(z => z.Number == y.Number)).ToList();
So What I need to do is to update employeeswithLatestChanges (Id,FirstName and LastName) with the values from existingEmployees from the database. Since they don't have Id, this should be mapped by the EmployeeNumber.
I have tried to use Union/joins but no luck.
Updating by linq in c# 6
var updatedEmployee = employeeswithLatestChanges.Select(x => new Employee
{
FirstName = existingEmployees.FirstOrDefault(y => y.EmployeeId == x.EmployeeNumber)?.FirstName?? x.FirstName,
LastName = existingEmployees.FirstOrDefault(y => y.LastName == x.code)?.LastName ?? x.LastName ,
});
Can Use Loop also
foreach (var dbEmp in existingEmployees)
{
foreach(var emp in (employeeswithLatestChanges.Where(t => t.EmployeeNumber == dbEmp.EmployeeId)))
{
emp.FirstName= dbEmp.FirstName;
emp.LastName= dbEmp.LastName;
}
}
To fix the idea we can assume the following class to represent an employee:
public sealed class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Guid Id { get; set; }
public int Number { get; set; }
}
Suppose you have a collection of employees named employees that you want to update by using another collection of employees named updatedEmployees:
IEnumerable<Employee> employees = ....;
IEnumerable<Employee> updatedEmployees = ....;
The simplest way I can think of to solve your problem is the following:
public static void Main(string[] args)
{
// previous code omitted for brevity
Dictionary<int, Employee> employeeNumberToUpdatedEmployee = updatedEmployees.ToDictionary(x => x.Number);
foreach (var employee in employees)
{
if (employeeNumberToUpdatedEmployee.TryGetValue(employee.Number, out var updatedEmployee)
{
employee.FirstName = updatedEmployee.FirstName;
employee.LastName = updatedEmployee.LastName;
}
}
// subsequent code omitted for brevity
}
An alternative way to solve this problem is to perform a join operation by using LINQ to objects, as in the following code:
var employees = new List<Employee>
{
new Employee{ Id = Guid.NewGuid(), Number = 11, FirstName = "Bob", LastName = "Red" },
new Employee{ Id = Guid.NewGuid(), Number = 13, FirstName = "Alice", LastName = "Smith" },
new Employee{ Id = Guid.NewGuid(), Number = 5, FirstName = "Max", LastName = "Brown" },
};
var updatedEmployees = new List<Employee>
{
new Employee{ Id = Guid.NewGuid(), Number = 11, FirstName = "Bob", LastName = "Verdi" },
new Employee{ Id = Guid.NewGuid(), Number = 13, FirstName = "Alice", LastName = "Rossi" },
new Employee{ Id = Guid.NewGuid(), Number = 78, FirstName = "Sam", LastName = "Smith" },
};
// here we are using the fact that we can have, at most, one match
var query = from employee in employees
join updatedEmployee in updatedEmployees on employee.Number equals updatedEmployee.Number into matches
from match in matches.DefaultIfEmpty()
select new Employee
{
Id = employee.Id,
Number = employee.Number,
FirstName = match?.FirstName ?? employee.FirstName,
LastName = match?.LastName ?? employee.LastName,
};
foreach (var item in query)
{
Console.WriteLine($"{item.FirstName} {item.LastName}");
}

Filter List inside List Linq

I have list say list of customers and inside each list there is another list of orders
Class Customer
{
int ID,
string Name
List<Order> orders
}
Class Order{
int ID,
string Name
}
Also have a integer list of filteredorderIds = {1,2,3,4}
I want to filter the list of customers who has got orderIds from filteredorderIds list.
So far I am stuck at query like
var filteredCustomers = Customers.Where(x => x.Orders.Any(filteredorderIds.contains(y => y.Id)));
please give credit to #Johnathan Barclay, since he posted faster than i typed example
void Main()
{
var customers = new List<Customer>(){
new Customer(){
ID =1,
Name = "Cust1",
orders = new List<Order>(){
new Order(){ID = 4, Name = "o11"},
new Order(){ID = 5, Name = "o12"},
new Order(){ID = 6, Name = "o13"}
}
},
new Customer(){
ID = 2,
Name = "Cust2",
orders = new List<Order>(){
new Order(){ID = 3, Name = "o21"},
new Order(){ID = 7, Name = "o22"},
new Order(){ID = 8, Name = "o23"}
}
}
};
customers.Where(w =>
w.orders.Any(w => filteredorderIds.Contains(w.ID))
).Dump();
}
List<int> filteredorderIds = new List<int>() { 1, 2, 3, 4 };
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public List<Order> orders { get; set; }
}
public class Order
{
public int ID { get; set; }
public string Name { get; set; }
}

Sort List of C# object by STRING parameter [duplicate]

This question already has answers here:
C# - code to order by a property using the property name as a string [duplicate]
(10 answers)
Closed 4 years ago.
I have a list of ListUser class objects. I need to be able to pass in a String value and order by that column in ascending or descending order using text expression. Everything I have seen that uses Lambda expressions, has the object property as a strongly typed value, How can I achieve this by adding in "firstname descending" as a parameter ?
The code is as follows
namespace SortLists
{
class ListUser
{
public int id { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public string company { get; set; }
public string phonenumber { get; set; }
}
class Program
{
static void Main(string[] args)
{
var user1 = new ListUser() { id = 1, firstname = "James", lastname = "Smith", company = "Code Logic", phonenumber = "01235 566 456" };
var user2 = new ListUser() { id = 1, firstname = "Chris", lastname = "Andrews", company = "Adobe", phonenumber = "01235 566 456" };
var user3 = new ListUser() { id = 1, firstname = "Paul", lastname = "Jones", company = "Microsoft", phonenumber = "01235 566 456" };
var user4 = new ListUser() { id = 1, firstname = "Peter", lastname = "Williams", company = "Apple", phonenumber = "01235 566 456" };
List<ListUser> users = new List<ListUser>()
{
user1, user2, user3, user4
};
}
}
Add reference to nuget package:
https://www.nuget.org/packages/System.Linq.Dynamic/
Add using System.Linq.Dynamic; at the top.
Use var usersSorted = users.AsQueryable().OrderBy("firstname ASC").ToList();
It's easy with a dictionary. Just start with this:
var sortBy = new Dictionary<string, Func<IEnumerable<ListUser>, IEnumerable<ListUser>>>()
{
{ "firstname", lus => lus.OrderBy(lu => lu.firstname) },
{ "lastname", lus => lus.OrderBy(lu => lu.lastname) },
{ "company", lus => lus.OrderBy(lu => lu.company) },
{ "phonenumber", lus => lus.OrderBy(lu => lu.phonenumber) },
};
Then you can easily sort like this:
List<ListUser> sorted = sortBy["firstname"](users).ToList();
If you want it descending just do this:
List<ListUser> sorted = sortBy["firstname"](users).Reverse().ToList();
Just structure your sort method like so:
if(stringPassed == "firstname")
{
List<ListUser> sortedListUser = listUser.OrderBy(p=>p.firstName).ToList();
}
else if(...) // and so on
if you want to order them by desc order just use LINQ's .OrderByDescending method.
The other cool approach may be that you set your properties to be objects with
string value;
string name;
and loop your input string with reflection towards the properties in your class and get the one you want and order it. It's a fancy way to impress your teacher xaxa.

How do I initialize this anonymous function?

var groups = new List<Group>
{
new Group{
Name = "Train",
Members = new List<Colleague>{
{FirstName = "Thomas", LastName = "Tank"},
{FirstName = "Honey", LastName = "Booboo"}
}
},
new Group{Name = "Bus"}
};
I am getting a red underline under 'FirstName' and 'LastName'... meaning that I've initialised it wrong...
How can I initialise that (Colleague) List? I think I am incorrectly initialising that list (Members)...
Edit: To make things clearer,
public class Group
{
public string Name { get; set; }
public List<Colleague> Members { get; set; }
}
Edit: Following up discussion with Kirk Woll:
This is what I did with your advice. Members is null though...
var groups = new List<Group>
{
new Group
{
Name = "Train",
Members = new List<Colleague>{
new Colleague { FirstName = "Thomas", LastName = "Tank" },
new Colleague { FirstName = "Jet", LastName = "Starr" }
}
},
new Group{Name = "Bus"}
};
To summarise, there's a breakpoint after the initialisation of groups. Each Group (x2) has Name defined, but Members = null in the first Group ('Train'). Members must be initialised! Cheers.
You want:
Members = new List<Colleague>
{
new Colleague { FirstName = "Thomas", LastName = "Tank" },
new Colleague { FirstName = "Honey", LastName = "Booboo" }
}
Since it's a list of Colleague to which you're trying to add it.

C# LINQ Take limited results per grouped

I have list that includes class named 'ID', 'Name' and 'Category'. There are 6 item in list.
List<MyData> list =
{
{0, "John", "Police"},
{1,"Michael", "Police"},
{2,"Alice", "Police"},
{3, "Ferdinand", "Thief"},
{4, "Jocas", "Thief"},
{5, "Connor", "Thief"}
};
I wanna list them with limited quantity per group by 'Category' with LINQ.
Example : I want list 2 item for each 'Cateogory'. Listed should be below :
John Police
Michael Police
Ferdinand Thief
Jocas Thief
Use combination of Take and SelectMany:
var results = list.GroupBy(x => x.Category).SelectMany(g => g.Take(2)).ToList();
I've tested it on following Item class:
public class Item
{
public int ID { get; set; }
public string Name { get; set; }
public string Category { get; set; }
}
And query:
List<Item> list = new List<Item>
{
new Item { ID = 0, Name = "John", Category = "Police"},
new Item { ID = 1, Name = "Michael", Category = "Police"},
new Item { ID = 2, Name = "Alice", Category = "Police"},
new Item { ID = 3, Name = "Ferdinand", Category = "Thief"},
new Item { ID = 4, Name = "Jocas", Category = "Thief"},
new Item { ID = 5, Name = "Connor", Category = "Thief"}
};
var results = list.GroupBy(x => x.Category).SelectMany(g => g.Take(2)).ToList();
Returns 4 elements, right as you want.

Categories