In this article, I describe how to convert a list of objects into a lookup collection. A sample project is also attached with this article.
Sometimes when we have a list of objects and we need to look up that collection by a member item in the object, we could easily benefit from converting a List collection into a Lookup collection. For example, we need to look up an entire product's inventory in a store by their Supply Date or by their price etc.
So, to get a Lookup from a list we use the extension method "ToLookup" available in a List collection's extension methods.
As per MSDN documentation:
List.ToLookup(Func<T, TKey> KeySelecter, Func<T, TElement> ElementSelecter, IEqualityComparer<TKey> Comparer) creates a Lookup<TKey, TElement> from an IEnumerable<T> (i.e. in this case our List) depending on the specified key selector and element selector functions.
Basically, a lookup is like a dictionary where the value associated with a key isn't one element but a sequence of elements. Lookups are generally used when duplicate keys are expected as part of normal operation.
Now we delve into the implementation of the Lookup conversion. Suppose we have a class "Product" having members (ID, Name, Price, Model, Brand, Availability, SaleItem). The class's Product declaration is as:
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public string Model { get; set; }
public string Brand { get; set; }
public string Availability { get; set; }
public string SaleItem { get; set; }
public Product(int id, string name, double price, string model, string brand, string availability, string sale)
{
this.ID = id;
this.Name = name;
this.Price = price;
this.Model = model;
this.Brand = brand;
this.Availability = availability;
this.SaleItem = sale;
}
}
Then we create a list of Product objects as:
List<Product> listProduct = new List<Product>()
{
new Product(1, "Mobile", 339.99, "ZZZ-B090-ZZZ-5","Samsung","Available","In Sale !"),
new Product(2, "Laptop", 514.99, "RRR-111-RRR-2","Toshiba", "Available", "Not in Sale"),
new Product(3, "Laptop", 554.99, "RRR-111-RRR-3", "Sony", "Available", "In Sale !"),
new Product(4, "Laptop", 414.99, "RRR-111-RRR-4","HP","Not Available","Not in Sale"),
new Product(5, "Phone", 112.99, "AAA-22-AAA-1","Samsung","Not Available","Not in Sale"),
new Product(6, "Phone", 156.99, "AAA-22-AAA-12","Samsung","Available", "Not in Sale"),
new Product(7, "PC", 313.69,"WWW-343-WWWW-03", "HP","Not Available","Not in Sale"),
new Product(8, "PC",363.69, "WWW-343-WWW-04", "Acer", "Available", "In Sale !"),
new Product(9, "AC",413.99, "NNN-80-NNN-342", "GE", "Not Available","Not in Sale"),
new Product(10, "Heater", 109.99,"TTT-318-TTT-424","Philips","Available","Not in Sale"),
new Product(11, "Heater", 79.99,"TTT-318-TTT-425", "GE", "Not Available","In Sale !"),
new Product(12, "Heater", 69.99, "TTT-318-TTT-426","Philips", "Available","In Sale !"),
};
Now suppose we need to show the collection by their brands, then we create a Lookup by their Brands in the following way:
ILookup<string,Product> lookupByBrand = listProduct.ToLookup(x => x.Brand, x => x);
Here the "x => x.Brand" portion serves as the KeySelector and the "x => x" portion serves as the ElementSelector.
Let us see how to iterate them. To iterate using a foreach loop, we may use a generic "var"
OR IGrouping<string,Product >.
// foreach (var product in lookupByBrand)
foreach (IGrouping<string,Product > product in lookupByBrand)
{
Console.WriteLine("\nItems of " + product.Key + " Brand [Quantity " + product.Count() + "]:\n");
foreach (Product p in product)
{
Console.Write(p.ID + "\t" + p.Name + "\t" + p.Model + "\t" + p.Price
+ "\t" + p.Brand + "\t" + p.Availability + "\t" + p.SaleItem);
Console.WriteLine();
}
}
On running this piece of code, we will get the following output:
Next we create a lookup that contains items by their availability. For that the code is as:
ILookup<string, Product> lookupByAvailablity = listProduct.ToLookup(x => x.Availability, x => x);
foreach (var product in lookupByAvailablity)
{
Console.WriteLine("\nFollowing items are '" + product.Key + "':\n");
foreach (Product p in product)
{
Console.Write(p.ID + "\t" + p.Name + "\t" + p.Model + "\t" + p.Price
+ "\t" + p.Brand + "\t" + p.Availability + "\t" + p.SaleItem);
Console.WriteLine();
}
}
And we get the output:
In the next piece of code, we create a collection such that we could easily determine which items are on "Sale" .
ILookup<string, Product> lookupBySale = listProduct.ToLookup(x => x.SaleItem, x => x);
foreach (IGrouping<string, Product> product in lookupBySale)
{
Console.WriteLine("\nFollowing items are '" + product.Key + "':\n");
foreach (Product p in product)
{
Console.Write(p.ID + "\t" + p.Name + "\t" + p.Model + "\t" + p.Price
+ "\t" + p.Brand + "\t" + p.Availability + "\t" + p.SaleItem);
Console.WriteLine();
}
}
Now suppose we are interested in finding the item that has a minimum price in the sale item list. This can be done easily by applying a lambda expression in the extension method as follows:
Product p1 = lookupBySale["In Sale !"].First(m => m.Price == (lookupBySale["In Sale !"].Min(y => y.Price)));
We can find more detail of how to use a lambda expression over a list (in any Enumerable object) in one of my previous articles:
http://www.c-sharpcorner.com/UploadFile/0f68f2/querying-a-data-table-using-select-method-and-lambda-express/
This time we get output like:
So far everytime we create a lookup, we set "KeySelector" as a Field and "ElementSelector" as an entire Product Object. We can also set our Key in the lookup as a part of a field (e.g. First letter of a Product Name) or any matching criteria. Similarly we are also free to choose any number of fields or an entire object in the ElementSelector part. See the following code:
ILookup<string, string> lookupByProductName =
listProduct.ToLookup(x => x.Name.Substring(0, 1), x => x.Name + "\t ($" + x.Price + ",\t" + x.Brand + ")");
foreach (IGrouping<string, string> productName in lookupByProductName)
{
Console.WriteLine("\nItem list with Letter '" + productName.Key + "':\n");
foreach (string p in productName.Distinct())
{
Console.Write(p);
Console.WriteLine();
}
}
The output of this code will be:
Hope the preceding explanation about "Getting Lookups from a List" will work for you!