Not getting Distinct Items when using Linq to List? - c#

Here is how I am attempting to get a distinct List of items...
var queryResults = PatientList.Distinct();
PatientList = queryResults.ToList<SelectListItem>();
For some reason, I am not getting a distinct list here.

Use
var queryResults = PatientList.GroupBy(x=>x.Id).Select(x=>x.FirstOrDefault())
PatientList = queryResults.ToList<SelectListItem>();
You can always try
PatientList = PatientList.GroupBy(x=>x.Id).Select(x=>x.FirstOrDefault()).ToList<SelectListItem>();
It will give you the distinct results based off whatever you group by
Check out http://blog.jordanterrell.com/post/LINQ-Distinct()-does-not-work-as-expected.aspx
Also another question for reference: Returning a Distinct IQueryable with LINQ?

Your SelectListItem class needs to override Equals and GetHashCode (and optionally implement IEquatable<SelectListItem>). Otherwise, different instances with the same values will be considered different.
Another option is to implement a IEqualityComparer<SelectListItem> and pass it as the second parameter to Distinct.

Not sure what kind of items your PatientList contains, but I guess you have to implement IEquatable on your custom object.
This have been aswered before here:
Distinct not working with LINQ to Objects

Related

Removing items found in another list

I have two lists and they are named: currentItems and newItems. newItems contains items found in currentItems and I am trying to those items before I output the list.
I have done some searching and I have tried using:
var newList = newItems.Except(CurrentItems).ToList();
but when I look at the output I still find the items from currentItems in the list. I found this example when I came across this question:
Quickest way to compare two List<>
which is similar to what I am trying to achieve but the all answers to the question do not work for me.
I have tried using:
List<ListItem> newList = newItems.Union(CurrentItems).ToList();
but I believe I am using it in the wrong situation since I am trying to remove the item completely from the list.
I have also tried looping through both loops, but I don't believe that is as efficient as it can be.
In the first example is there something I may be doing wrong with it? Or is there a different way to achieve my goal?
IEnumerable.Except will do what you want but it uses the default equality comparer. For custom objects you will need to implement Equals and GetHashCode
Also note that if newItems has duplicate values IEnumerable.Except will also do a distinct on your list.
EDIT2: You need an equality comparer that compares ListItem's I believe.
You'll need to pass in a custom comparor that compares just the Value property of the ListItem.
var newList = newItems.Except(currentItems, new ListItemValueComparer());
And the custom equality comparer is here...
class ListItemValueComparer : IEqualityComparer<ListItem>
{
public bool Equals(ListItem x, ListItem y)
{
return x.Value.Equals(y.Value);
}
public int GetHashCode(ListItem obj)
{
return obj.Value.GetHashCode();
}
}

Need help figuring out what this C# code does

I am going through a tutorial for asp.net and C# and the author used some code that I am trying to understand. I have an idea of what it does, but I just wanted to make sure.
public IQueryable<Category> GetCategories()
{
var db = new WingtipToys.Models.ProductContext();
IQueryable<Category> query = db.Categories;
return query;
}
I am a little confused by
IQueryable<Category>
as well as the line
IQueryable<Category> query = db.Categories;
What I think it does is that it is a method called GetCategories() that only accepts Category objects. The method defines a new instance productcontext, it then runs some type of query and returns it. I could be close or way off. I just want to make sure.
... method called GetCategories() that only accepts Category objects ...
IQueryable<Category> is a type just like intor string so the method accepts nothing, it judt returns categories in a queryable way (IQueryable).
The IQueryable return type is used to indicate you want C# to pass along any filters that you use on the GetCategories() method to be passed directly to the database. Even though the method is setup to pass all categories back, you can limit them at a higher level. This saves you from having to create multiple methods for each filter you can think of that goes back to the database.
Here is link to a StackOverflow Example about the differences between IEnumerable and IQueryable
So I think the part you're having trouble with is the generic return type in the method signature, it can be a strange syntax if you haven't come across it before.
Your method is returning a type of IQueryable<Category>, so you're going to be returning an object that implements the interface IQueryable<T>, specifically one which is implemented to work specifically with Category objects.
If you wanted to create a list of strings, you'd do something like:
MyStrings = new List<string>();
And if you wanted to create a method to return a list of strings:
public List<string> FetchMyStrings(); // List<string> is your return type.
In your case, you're returning a list of Category objects:
public List<Category> FetchMyCategories(); // List<Category> is your return type.
For some excellent explanations of IQueryable<T>, and why you'd be interested in it, I'd recommend the answers here:
What is the difference between IQueryable<T> and IEnumerable<T>?
The rest of the code seems to initialise a new database connection, and returns a queryable object, allowing you to get at the categories for use elsewhere in your code.

List<T> Where T is custom object. Remove duplicates by property

I have a List<T> where T is a custom object. None of my object are equal but some might have an equal property. Is there any fast way to remove the duplicates by comparing the property? It doesn't matter which of the duplicates stays in the list.
You can use List<T>.RemoveAll to do this efficiently.
For example, if you wanted to remove all elements where the Foo property had a value of 42, you could do:
theList.RemoveAll(i => i.Foo == 42);
If you're trying to make a list of distinct items by a property, ie: keep only distinct Foo items, I would recommend doing something like:
HashSet<int> elements = new HashSet<int>(); // Type of property
theList.RemoveAll(i => !elements.Add(i.Foo));
This will track which elements are "distinct" and remove all others.
Group the objects based on the property value, then pick the first item in each group. Like this:
var distinctObjects = objects
.GroupBy(x => x.Property)
.Select(g => g.First());
You can create a new class that implements IEqualityComparer<T> by comparing the property. Then you can use linq's Distinct method to get an IEnumerable that contains only the unique elements.
you can also use a very good library from here http://powercollections.codeplex.com/ and use Algorithms.RemoveDuplicates method. That library has many more other goodies on collections.

Adding an element to an ArrayList which is nested inside a HashTable (turtles all the way down)

I have this code which, on the front-end, will create dependent selectboxes (subcategories are dependent on the category) using LINQ:
foreach (var cat in (from category in KB.Categories
orderby category.name
select category)) {
this.categories.Add(cat.id, cat.name);
}
foreach (var sub_cat in (from subcategory in KB.SubCategories
orderby subcategory.name
select subcategory)) {
this.subcategories.Add(sub_cat.id, sub_cat.name);
if (!this.subcategoryCategory.containsKey) {
this.subcategoryCategory.Add(sub_cat.category_id, new ArrayList());
}
// I'd like to put the sub_cat_id at the end of the arraylist
// for the category_id, but this line doesn't seem to work
//this.subcategoryCategory[sub_cat.category_id] = sub_cat.id;
}
How can I do this?
Perhaps there a way to build a giant JSON object instead of the three variables (categories, subCategoryCategory, subcategories)?
Is there a better/different way to do this that I've completely missed?
P.S. Coming from a different programming paradigm, I'm not doing this in the standard ASP.NET (webforms or MVC) way, but I am using codebehind to generate the values.
It looks like you actually want a Lookup, e.g.
var subcategories = KB.SubCategories.ToLookup(subcat => subcat.id,
subcat => subcat.name);
However, it's not really clear given that you've got subcategories, subcategoryCategory and categoies, all of which are instance variables which you haven't shown us the type for... and your if clause doesn't specify which key it's trying to use. It's all a bit confused at the moment...
My guess is that you should look at ToLookup and also ToDictionary, which are made for this sort of thing.
JSON.NET might solve this problem, with its ability to convert JSON objects to C# and back. See this SO question for an example.

How to modify an item in an IEnumerable collection and retain its order

I have the following situation. I have a list of items which have an "Id". I have to search for an item with a specific id, modify its values and maintain the order of the collection. What would be the best way to do that?
var collection = <some_linq_query>
collection.Where(i=>i.Id=someId).FirstOrDefault().Property = "bla";
// now collection should be the same but the item updated.
The call to Where does not modify the original LINQ query stored in collection in any way. Instead it creates a new IEnumerable<T> where is a subset of the original query. The subset will have the same relative ordering as the original set in collection
The only way this could cause a problem is if the value collection is a LINQ where which has a Where clause, or is otherwise filtered, base on the value of Property. If that is the case and you want to preserve the order force collection into a non-lazy evaluated structure via .ToList.
collection = collection.ToList();
As long as the objects in the collection are mutable, your code should work fine.
By the way, FirstOrDefault takes an optional filter parameter, so you can write collection.FirstOrDefault(i => i.Id == someId).

Categories