Comparing code prior to LINQ - c#

I am trying to get an idea of what c# code looked like before LINQ came out.
I have tried searching for this for several weeks and came up empty. I understand how LINQ works but say you have a list of objects but you are trying to just locate a small amount. How would you have done this before LINQ?
Example of LINQ (excuse my syntax error, I'm still learning) :)
list<employee> newlist = new List<employee> {john, smith, 30}
newlist.add{jane, smith, 28}
newlist.add{greg, lane, 24}
var last
from name in newlist
where name.last.equals("smith")
select name
foreach(var name in last)
{
Console.WriteLine(last);
}
How would you be able to sort through and locate the name of employees by last name and display them?

It's really the same number of lines of code, just more curley braces.
Here's a translation:
List<employee> newList = new List<employee>
{
new employee {First = john, Last = smith, Age = 30},
new employee {First = jane, Last = smith, Age = 28},
new employee {First = greg, Last = lane, Age = 24},
}
// Original code: // Pre-Linq translation:
var last // Becomes: var last = new List<employee>();
from name in newList // Becomes: foreach (var name in newList) {
where name.Last.Equals("smith") // Becomes: if (name.Last.Equals("smith") {
select name // Becomes: last.Add(name) } }
// Pre-Linq code:
var last = new List<employee>();
foreach (var name in newList)
{
if (name.Last.Equals("smith")
{
last.Add(name)
}
}

Just the traditional way. Loop through and filter.
var smiths = new List<string>();
foreach (var employee in newlist)
{
if(employee.Last == "smith")
{
smiths.Add(employee);
}
}
return smiths;
For sorting, you can pass a delegate to the Sort() method. LINQ is just syntactic sugar on top of it.
newlist.Sort(delegate(Employee e1, Employee e2)
{
//your comparison logic here that compares two employees
});
Another way to sort is to create a class that implements IComparer and pass that to the sort method
newlist.Sort(new LastNameComparer());
class LastNameComparer: IComparer<Employee>
{
public int Compare(Employee e1, Employee e2)
{
// your comparison logic here that compares two employees
return String.Compare(e1.Last, e2.Last);
}
}
Looking at all this code, LINQ is such a time saver :)

Pretty easy. You are looping through all your items in a list and taking(mean copying references to other list) the ones you are looking for:
var smiths = new List<Persons>();
// get all Smiths and print them
foreach(var item in newlist)
{
if(item.last == "smith")
smiths.Add(item);
}
foreach(var item in smiths)
{
Console.WriteLine(item);
}

Related

LINQ: Query Syntax - How can I identify everyone who has a higher income than someone else?

So I have to identify everyone who has a higher income than "JONES".
Here is the Schema:
new Emp{name = "SMITH", income = 800},
new Emp{name = "JONES", income = 600},
new Emp{name = "ADAMS", income = 900},
new Emp{name = "KING", income = 400}
I can't find a way to build this in a Query Syntax...
so let's say you have your data like this. so this should solve your problem. so to explain the code below.
I have a list of data based of the Emp class.
I also have a variable of jones that contains information about jones.
I can then use Linq to query the data list of Emp where the emp income is greater than the matches Jones. then I return then in orderbydescending using Linq.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
//Emp class for
public class Emp
{
public string name { get; set; }
public double income { get; set; }
}
public static void Main()
{
//List of Emp data base off the Emp class object.
var data = new List<Emp>
{
new Emp {name = "SMITH", income = 800},
new Emp {name = "JONES", income = 600},
new Emp {name = "ADAMS", income = 900},
new Emp {name = "KING", income = 400}
};
//Jones data that will be used for querying
var jones = new Emp {name = "JONES", income = 600};
//List of Emp that have income higher than jones.
var higherThanJones = data.Where(item => item.income > jones.income)
.OrderByDescending(i => i.income)
.ToList();
//Foreach loop to show the people with income than jones
foreach (var people in higherThanJones)
{
//printing out the names of the people higher than Jones
Console.WriteLine(people.name);
}
}
}
In query syntax, you can first create a query to find the matching record, or return the default (which will be 0) if there is no match:
var jonesIncome = (from e in emps
where e.name == "JONES"
select e.income).FirstOrDefault();
Then you can use the income query to find the rows desired:
var higherThanJones = from e in emps
where e.income > jonesIncome
select e;
Since queries use deferred execution, the two queries will actually be executed when higherThanJones results are used. If you are querying a database, the two queries will be translated into a single SQL query, depending on the LINQ you are using and the database provider.
You could also use lambda/fluent syntax to combine into a single query (I prefer not to combine query syntax as it doesn't read as well):
var matchName = "JONES";
var higherThanMatch = emps.Where(e => e.income > emps.Where(e2 => e2.name == matchName)
.Select(e2 => e2.income)
.FirstOrDefault());
So I have to identify everyone who has a higher income than "JONES".
Are you certain there is a "Jones"? Is there exactly one "Jones"?
The answer depends on whether you are working IQueryable or IEnumerable.
If you need to do it as Queryable, you need to pack it in one Query:
IQueryable<Employee> employees = ...
var employeesWithHigherIncomes = employees
.Where(employee => employee.Income >
employees.Where(employee => employee.Name == name)
.FirstOrDefault()));
Luckily your database is smart enough not to search Jones again for every Employee.
As Enumerable:
string name = "Jones"
IEnumerable<Employee> employees = ...
var incomeJones = employees.Where(employee => employee.Name == name)
.Select(employee => employee.Income)
.FirstOrDefault();
var employessWithHigherIncome = employees
.Where(employee => employee.Income > incomeJones)
.FirstOrDefault();
You will enumerate your sequence at utmost twice: once (partly) until you found the first "Jones", and once completely to find all higher incomes.
If I had put the query to find the income of Jones in the "Where", like I did in Queryable, then for every Employee I had to enumerate the sequence to find Jones again.

How can I add certain values from one list to another list in .NET

I have created 2 lists in my code. One contains a long lists of employee's first and last names, followed by their index:
public List<Employee> FindTestEmployees()
{
var results = SubmitQuery($#"(Select distinct(E.Badge_Sys_No), E.Emp_Id, E.Last_Nm, E.First_Nm,e.emp_job_func_cd
From Employee E, Employee_Job_Func Ef, Emp_Job_Function_Group_Asgnmt Ejfga
Where .....");
var EmployeeList = new List<Employee>();
for (var i = 0; i < results.Rows.Count; i++)
{
var employee = new Employee();
employee.FirstName = results.Rows[i][3].ToString();
employee.LastName = results.Rows[i][2].ToString();
employee.Index = i;
EmployeeList.Add(employee);
EmployeeList.Add(employee);
}
return EmployeeList;
}
The second is a short list of employees who have reports previously generated for them. This list only contains the employee's first and last names:
public List<Employee> FindIPCREmployees()
{
var results = SubmitQuery($#"(Select E.first_nm, e.last_nm, Ejfga.Emp_Job_Function_Group_Cd,
e.emp_job_func_cd
From Interaction I, Interaction_Activity Ia, Appointment A, Branch B,
Employee E, Employee_Job_Func Ef, Emp_Job_Function_Group_Asgnmt Ejfga
Where .....)");
var IPCREmployeesList = new List<Employee>();
for (var i = 0; i < results.Rows.Count; i++)
{
var employee = new Employee();
employee.FirstName = results.Rows[i][0].ToString();
employee.LastName = results.Rows[i][1].ToString();
IPCREmployeesList.Add(employee);
}
return IPCREmployeesList;
}
What I'm trying to do is create a third list that will contain the first and last names of employees from the second list and the index of that specific employee from the 1st list. The important part being the link between the lists by the name of the employee.
Is there a way of doing this in .NET? If so I would really appreciate the help.
Assuming I'm creating the final list you are looking for correctly:
var employeeList = FindTestEmployees();
var secondList = FindIPCREmployees();
var finalList = employeeList.Join(secondList, a => new {a.FirstName, a.LastName}, b => {b.FirstName, b.LastName}, (a,b) => a);
In this case finalList will be a collection of Employee objects from the first list that had entries with a matching first and last name in your second list. I recommend becoming good friends with LINQ if .NET is where you're spending your time.
I believe you need a Dictionary<Employee,int>:
Dictionary<Employee,int> dict=new Dictionary<Employee,int>();
foreach (var employee in IPCREmployeesList)
{
dict.Add(employee,EmployeeList.IndexOf(employee));
}

How to remove item from list in C#?

I have a list stored in resultlist as follows:
var resultlist = results.ToList();
It looks something like this:
ID FirstName LastName
-- --------- --------
1 Bill Smith
2 John Wilson
3 Doug Berg
How do I remove ID 2 from the list?
List<T> has two methods you can use.
RemoveAt(int index) can be used if you know the index of the item. For example:
resultlist.RemoveAt(1);
Or you can use Remove(T item):
var itemToRemove = resultlist.Single(r => r.Id == 2);
resultList.Remove(itemToRemove);
When you are not sure the item really exists you can use SingleOrDefault. SingleOrDefault will return null if there is no item (Single will throw an exception when it can't find the item). Both will throw when there is a duplicate value (two items with the same id).
var itemToRemove = resultlist.SingleOrDefault(r => r.Id == 2);
if (itemToRemove != null)
resultList.Remove(itemToRemove);
Short answer:
Remove (from list results)
results.RemoveAll(r => r.ID == 2); will remove the item with ID 2 in results (in place).
Filter (without removing from original list results):
var filtered = result.Where(f => f.ID != 2); returns all items except the one with ID 2
Detailed answer:
I think .RemoveAll() is very flexible, because you can have a list of item IDs which you want to remove - please regard the following example.
If you have:
class myClass {
public int ID; public string FirstName; public string LastName;
}
and assigned some values to results as follows (used for all examples below):
var results = new List<myClass> {
new myClass { ID=1, FirstName="Bill", LastName="Smith" }, // results[0]
new myClass { ID=2, FirstName="John", LastName="Wilson" }, // results[1]
new myClass { ID=3, FirstName="Doug", LastName="Berg" }, // results[2]
new myClass { ID=4, FirstName="Bill", LastName="Wilson" } // results[3]
};
Then you can define a list of IDs to remove:
var removeList = new List<int>() { 2, 3 };
And simply use this to remove them:
results.RemoveAll(r => removeList.Any(a => a==r.ID));
It will remove the items 2 and 3 and keep the items 1 and 4 - as specified by the removeList. Note that this happens in place, so there is no additional assigment required.
Of course, you can also use it on single items like:
results.RemoveAll(r => r.ID==4);
where it will remove Bill with ID 4 in our example.
A last thing to mention is that lists have an indexer, that is, they can also be accessed like a dynamic array, i.e. results[3] will give you the 4th element in the results list (because the first element has the index 0, the 2nd has index 1 etc).
So if you want to remove all entries where the first name is the same as in the 4th element of the results list, you can simply do it this way:
results.RemoveAll(r => results[3].FirstName == r.FirstName);
Note that afterwards, only John and Doug will remain in the list, Bill is removed (the first and last element in the example). Important is that the list will shrink automatically, so it has only 2 elements left - and hence the largest allowed index after executing RemoveAll in this example is 1 (which is results.Count() - 1).
Some Trivia:You can use this knowledge and create a local function
void myRemove() { var last = results.Count() - 1;
results.RemoveAll(r => results[last].FirstName == r.FirstName); }
What do you think will happen, if you call this function twice?
Like
myRemove(); myRemove();
Answer (click to show):
The first call will remove Bill at the first and last position, the second call will remove Doug and only John Wilson remains in the list.
Note: Since C# Version 8, you can as well write results[^1] instead of var last = results.Count() - 1; and results[last]:
void myRemove() => results.RemoveAll(r => results[^1].FirstName == r.FirstName);
So you would not need the local variable last anymore (see indices and ranges). Furthermore, since it is a one-liner, you don't require the curly braces and can use => instead.
For a list of all the new features in C#, look here.
DotNetFiddle: Run the demo
resultList = results.Where(x=>x.Id != 2).ToList();
There's a little Linq helper I like that's easy to implement and can make queries with "where not" conditions a little easier to read:
public static IEnumerable<T> ExceptWhere<T>(this IEnumerable<T> source, Predicate<T> predicate)
{
return source.Where(x=>!predicate(x));
}
//usage in above situation
resultList = results.ExceptWhere(x=>x.Id == 2).ToList();
You don't specify what kind of list, but the generic List can use either the RemoveAt(index) method, or the Remove(obj) method:
// Remove(obj)
var item = resultList.Single(x => x.Id == 2);
resultList.Remove(item);
// RemoveAt(index)
resultList.RemoveAt(1);
More simplified:
resultList.Remove(resultList.Single(x => x.Id == 2));
there is no needing to create a new var object.
There is another approach. It uses List.FindIndex and List.RemoveAt.
While I would probably use the solution presented by KeithS (just the simple Where/ToList) this approach differs in that it mutates the original list object. This can be a good (or a bad) "feature" depending upon expectations.
In any case, the FindIndex (coupled with a guard) ensures the RemoveAt will be correct if there are gaps in the IDs or the ordering is wrong, etc, and using RemoveAt (vs Remove) avoids a second O(n) search through the list.
Here is a LINQPad snippet:
var list = new List<int> { 1, 3, 2 };
var index = list.FindIndex(i => i == 2); // like Where/Single
if (index >= 0) { // ensure item found
list.RemoveAt(index);
}
list.Dump(); // results -> 1, 3
Happy coding.
Try this code:
resultlist.Remove(resultlist.Find(x => x.ID == 2));
... or just resultlist.RemoveAt(1) if you know exactly the index.
{
class Program
{
public static List<Product> list;
static void Main(string[] args)
{
list = new List<Product>() { new Product() { ProductId=1, Name="Nike 12N0",Brand="Nike",Price=12000,Quantity=50},
new Product() { ProductId =2, Name = "Puma 560K", Brand = "Puma", Price = 120000, Quantity = 55 },
new Product() { ProductId=3, Name="WoodLand V2",Brand="WoodLand",Price=21020,Quantity=25},
new Product() { ProductId=4, Name="Adidas S52",Brand="Adidas",Price=20000,Quantity=35},
new Product() { ProductId=5, Name="Rebook SPEED2O",Brand="Rebook",Price=1200,Quantity=15}};
Console.WriteLine("Enter ProductID to remove");
int uno = Convert.ToInt32(Console.ReadLine());
var itemToRemove = list.Find(r => r.ProductId == uno);
if (itemToRemove != null)
list.Remove(itemToRemove);
Console.WriteLine($"{itemToRemove.ProductId}{itemToRemove.Name}{itemToRemove.Brand}{itemToRemove.Price}{ itemToRemove.Quantity}");
Console.WriteLine("------------sucessfully Removed---------------");
var query2 = from x in list select x;
foreach (var item in query2)
{
/*Console.WriteLine(item.ProductId+" "+item.Name+" "+item.Brand+" "+item.Price+" "+item.Quantity );*/
Console.WriteLine($"{item.ProductId}{item.Name}{item.Brand}{item.Price}{ item.Quantity}");
}
}
}
}

how to query LIST using linq

Suppose if I add person class instance to list and then I need to query the list using linq.
List lst=new List();
lst.add(new person{ID=1,Name="jhon",salary=2500});
lst.add(new person{ID=2,Name="Sena",salary=1500});
lst.add(new person{ID=3,Name="Max",salary=5500});
lst.add(new person{ID=4,Name="Gen",salary=3500});
Now I want to query the above list with linq. Please guide me with sample code.
I would also suggest LinqPad as a convenient way to tackle with Linq for both advanced and beginners.
Example:
Well, the code you've given is invalid to start with - List is a generic type, and it has an Add method instead of add etc.
But you could do something like:
List<Person> list = new List<Person>
{
new person{ID=1,Name="jhon",salary=2500},
new person{ID=2,Name="Sena",salary=1500},
new person{ID=3,Name="Max",salary=5500}.
new person{ID=4,Name="Gen",salary=3500}
};
// The "Where" LINQ operator filters a sequence
var highEarners = list.Where(p => p.salary > 3000);
foreach (var person in highEarners)
{
Console.WriteLine(person.Name);
}
If you want to learn details of what all the LINQ operators do, and how they can be implemented in LINQ to Objects, you might be interested in my Edulinq blog series.
var persons = new List<Person>
{
new Person {ID = 1, Name = "jhon", Salary = 2500},
new Person {ID = 2, Name = "Sena", Salary = 1500},
new Person {ID = 3, Name = "Max", Salary = 5500},
new Person {ID = 4, Name = "Gen", Salary = 3500}
};
var acertainperson = persons.Where(p => p.Name == "jhon").First();
Console.WriteLine("{0}: {1} points",
acertainperson.Name, acertainperson.Salary);
jhon: 2500 points
var doingprettywell = persons.Where(p => p.Salary > 2000);
foreach (var person in doingprettywell)
{
Console.WriteLine("{0}: {1} points",
person.Name, person.Salary);
}
jhon: 2500 points
Max: 5500 points
Gen: 3500 points
var astupidcalc = from p in persons
where p.ID > 2
select new
{
Name = p.Name,
Bobos = p.Salary*p.ID,
Bobotype = "bobos"
};
foreach (var person in astupidcalc)
{
Console.WriteLine("{0}: {1} {2}",
person.Name, person.Bobos, person.Bobotype);
}
Max: 16500 bobos
Gen: 14000 bobos
Since you haven't given any indication to what you want, here is a link to 101 LINQ samples that use all the different LINQ methods: 101 LINQ Samples
Also, you should really really really change your List into a strongly typed list (List<T>), properly define T, and add instances of T to your list. It will really make the queries much easier since you won't have to cast everything all the time.

Filtering collections in C#

I am looking for a very fast way to filter down a collection in C#. I am currently using generic List<object> collections, but am open to using other structures if they perform better.
Currently, I am just creating a new List<object> and looping thru the original list. If the filtering criteria matches, I put a copy into the new list.
Is there a better way to do this? Is there a way to filter in place so there is no temporary list required?
If you're using C# 3.0 you can use linq, which is way better and way more elegant:
List<int> myList = GetListOfIntsFromSomewhere();
// This will filter ints that are not > 7 out of the list; Where returns an
// IEnumerable<T>, so call ToList to convert back to a List<T>.
List<int> filteredList = myList.Where(x => x > 7).ToList();
If you can't find the .Where, that means you need to import using System.Linq; at the top of your file.
Here is a code block / example of some list filtering using three different methods that I put together to show Lambdas and LINQ based list filtering.
#region List Filtering
static void Main(string[] args)
{
ListFiltering();
Console.ReadLine();
}
private static void ListFiltering()
{
var PersonList = new List<Person>();
PersonList.Add(new Person() { Age = 23, Name = "Jon", Gender = "M" }); //Non-Constructor Object Property Initialization
PersonList.Add(new Person() { Age = 24, Name = "Jack", Gender = "M" });
PersonList.Add(new Person() { Age = 29, Name = "Billy", Gender = "M" });
PersonList.Add(new Person() { Age = 33, Name = "Bob", Gender = "M" });
PersonList.Add(new Person() { Age = 45, Name = "Frank", Gender = "M" });
PersonList.Add(new Person() { Age = 24, Name = "Anna", Gender = "F" });
PersonList.Add(new Person() { Age = 29, Name = "Sue", Gender = "F" });
PersonList.Add(new Person() { Age = 35, Name = "Sally", Gender = "F" });
PersonList.Add(new Person() { Age = 36, Name = "Jane", Gender = "F" });
PersonList.Add(new Person() { Age = 42, Name = "Jill", Gender = "F" });
//Logic: Show me all males that are less than 30 years old.
Console.WriteLine("");
//Iterative Method
Console.WriteLine("List Filter Normal Way:");
foreach (var p in PersonList)
if (p.Gender == "M" && p.Age < 30)
Console.WriteLine(p.Name + " is " + p.Age);
Console.WriteLine("");
//Lambda Filter Method
Console.WriteLine("List Filter Lambda Way");
foreach (var p in PersonList.Where(p => (p.Gender == "M" && p.Age < 30))) //.Where is an extension method
Console.WriteLine(p.Name + " is " + p.Age);
Console.WriteLine("");
//LINQ Query Method
Console.WriteLine("List Filter LINQ Way:");
foreach (var v in from p in PersonList
where p.Gender == "M" && p.Age < 30
select new { p.Name, p.Age })
Console.WriteLine(v.Name + " is " + v.Age);
}
private class Person
{
public Person() { }
public int Age { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
}
#endregion
List<T> has a FindAll method that will do the filtering for you and return a subset of the list.
MSDN has a great code example here: http://msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx
EDIT: I wrote this before I had a good understanding of LINQ and the Where() method. If I were to write this today i would probably use the method Jorge mentions above. The FindAll method still works if you're stuck in a .NET 2.0 environment though.
You can use IEnumerable to eliminate the need of a temp list.
public IEnumerable<T> GetFilteredItems(IEnumerable<T> collection)
{
foreach (T item in collection)
if (Matches<T>(item))
{
yield return item;
}
}
where Matches is the name of your filter method. And you can use this like:
IEnumerable<MyType> filteredItems = GetFilteredItems(myList);
foreach (MyType item in filteredItems)
{
// do sth with your filtered items
}
This will call GetFilteredItems function when needed and in some cases that you do not use all items in the filtered collection, it may provide some good performance gain.
To do it in place, you can use the RemoveAll method of the "List<>" class along with a custom "Predicate" class...but all that does is clean up the code... under the hood it's doing the same thing you are...but yes, it does it in place, so you do same the temp list.
You can use the FindAll method of the List, providing a delegate to filter on. Though, I agree with #IainMH that it's not worth worrying yourself too much unless it's a huge list.
If you're using C# 3.0 you can use linq
Or, if you prefer, use the special query syntax provided by the C# 3 compiler:
var filteredList = from x in myList
where x > 7
select x;
Using LINQ is relatively much slower than using a predicate supplied to the Lists FindAll method. Also be careful with LINQ as the enumeration of the list is not actually executed until you access the result. This can mean that, when you think you have created a filtered list, the content may differ to what you expected when you actually read it.
If your list is very big and you are filtering repeatedly - you can sort the original list on the filter attribute, binary search to find the start and end points.
Initial time O(n*log(n)) then O(log(n)).
Standard filtering will take O(n) each time.

Categories