Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unique list of items using LINQ

Tags:

I've been using LINQ for a while now, but seem to be stuck on something with regards to Unique items, I have the folling list:

List<Stock> stock = new List<Stock>(); 

This has the following Properties: string ID , string Type, string Description, example:

public class Stock {     public string ID { get; set; }     public string Type { get; set; }     public string Description { get; set; } } 

I want to have a LINQ query that will group the items in Stock by their Type and return this as a new List of Stock (it has to be the same type as the original Stock List).

Example Data:

 ID   Type                 Description ----------------------------------------------   1   Kitchen Appliance    Dishwasher     2   Living Room          Television     3   Kitchen Appliance    Washing Machine     4   Kitchen Appliance    Fridge   

...

My Linq query wants to be able to return all the Kitchen Appliances for Example.
So I would pass this as a "type" into the query and it would return the items 1, 3 and 4 from this example list.

This list returned must also be of type: List<Stock>.

Essentially I want a list of the unique items by type, kind of like an SQL Distinct query, how do I achieve this in LINQ?
Alternative solutions are fine but must be Silverlight / C# client code only.

Just another clarification is that I also may not provide the parameter "Kitchen Appliance" and may just want the unique ones, for example It would return Kitchen Appliance and Living Room once each only to kind of like a category no matter how many of that Type there are.

like image 592
RoguePlanetoid Avatar asked Jul 06 '10 13:07

RoguePlanetoid


People also ask

How do I get distinct on a single column in LINQ?

distinct in Linq to get result based on one field of the table (so do not require a whole duplicated records from table). I know writing basic query using distinct as followed: var query = (from r in table1 orderby r. Text select r).

Why distinct is not working in LINQ?

LINQ Distinct is not that smart when it comes to custom objects. All it does is look at your list and see that it has two different objects (it doesn't care that they have the same values for the member fields). One workaround is to implement the IEquatable interface as shown here.

What is distinct LINQ?

C# Linq Distinct() method removes the duplicate elements from a sequence (list) and returns the distinct elements from a single data source. It comes under the Set operators' category in LINQ query operators, and the method works the same way as the DISTINCT directive in Structured Query Language (SQL).

What are the uses of LINQ to objects?

In a nutshell, LINQ to Objects provides the developer with the means to conduct queries against an in-memory collection of objects. The techniques used to query against such collections of objects are similar to but simpler than the approaches used to conduct queries against a relational database using SQL statements.


2 Answers

Flexible approach

Use GroupBy and ToDictionary to create a dictionary of List<Stock> values keyed on the Type property:

var appliancesByType = stock     .GroupBy(item => item.Type)     .ToDictionary(grp => grp.Key, grp => grp.ToList()); 

Then you can access the types themselves as well as a list for any given type quite easily:

// List of unique type names only List<string> stockTypes = appliancesByType.Keys.ToList();  // Or: list of one stock item per type List<Stock> exampleStocks = appliancesByType     .Select(kvp => kvp.Value[0])     .ToList();  // List of stock items for a given type List<Stock> kitchenAppliances = appliancesByType["Kitchen Appliance"]; 

This approach really takes care of all your needs, as I see it. But for some other options, see below.

Alternate (quick & dirty) approach

You can always just use Where to get the items of the type you want, then ToList to put these items in a new List<Stock>:

List<Stock> kitchenAppliances = stock     .Where(item => item.Type == "Kitchen Appliance")     .ToList(); 

In response to this last part:

Just another clarification is that I also may not provide the parameter "Kitchen Appliance" and may just want the unique ones, for example It would return Kitchen Appliance and Living Room once each only to kind of like a category no matter how many of that Type there are.

Here, you seem to be wanting something completely different: basically the behavior provided by Distinct. For this functionality, you could essentially go with Soonts's answer (optionally, returning an IEnumerable<tKey> instead of IEnumerable<tSource>), or you could just leverage Distinct in combination with Select to avoid the need to implement an IEqualityComparer<Stock> (see below).


Update

In response to your clarification, here's my recommendation: two methods, one for each purpose (Single Responsibility Principle):

// This will return a list of all Stock objects having the specified Type static List<Stock> GetItemsForType(string type) {     return stock         .Where(item => item.Type == type)         .ToList(); }  // This will return a list of the names of all Type values (no duplicates) static List<string> GetStockTypes() {     return stock         .Select(item => item.Type)         .Distinct()         .ToList(); } 
like image 177
Dan Tao Avatar answered Nov 18 '22 09:11

Dan Tao


Sounds like it's a simple Where clause needed.

List<Stock> kitchen= stock.Where(s=>s.Type=="Kitchen Appliance")                           .OrderBy(s=>s.Description).ToList(); 

If you wanted strictly the Types contained in the source list:

string[] typesFound = stock.Select(s=>s.Type).Distinct().ToArray();

like image 27
p.campbell Avatar answered Nov 18 '22 09:11

p.campbell