LINQ get elements from one collection that don't belong to another - c#

I have a List<MyObject> allObjects and List<MyObject> someObjects (all of the objects in someObjects belongs to allObjects too. I want to get the elements from allObjects which doesn't belong to someObjects ? How can I achieve that with LINQ ?

It's as easy as allObjects.Except(someObjects)
However, you should be aware that this uses the default equality comparer under the covers to compare the values.
If you wish to use a custom IEqualityComparer<MyObject>, there's an overload that allows you to do just that.

var exceptionList= allObjects.Except(someObjects);

Try this
allObjects.Except(someObjects)

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();
}
}

What collection class should we use to manage and merge list of objects using C#?

I'm looking for a collection to manage and merge list of objects using C# ? Do you know where I can find a good tutorial abour collections ?
Actally I'm looking to merge two or three list of objects/entities. These lists can contains the same object (identical id). The merged list should contain only one version of each object/entities. Then I should order the list on a property.
Depending on how you want to merge your collections, you could use any collection that implements IEnumerable<T>, as this interface provides the Union(IEnumerable<T>) method that "merges" and removes duplicates.
You then might want to implement IEqualityComparer<T> to compare your objects using their identity (ID) property.
You could use a HashSet<T> with a custom IEqualityComparer<T>. Or you could use a Dictionary<T1, T2> where T1 is your ID.

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.

Not getting Distinct Items when using Linq to List?

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

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