I have three seperate ToSelectList items and i wanted to combine each list into one dropdown list box and was wondering if i could use a Union for it. Or is it that a union is only for 2 toselectlist items only.
Thanks!
When item exists in more than one list, do you want item to appear once, or as many times as they exists in all lists?
As I understand you want just concat:
var combinedList = list1.Concat(list2).Concat(list3).ToList();
If you want to avoid duplicates:
var unionList = list1.Union(list2).Union(list3).ToList();
Union is more expensive, as it has to go through the list and take care of duplicates.
If your item is a reference type and there is no IComparable or IEquable interfaces and you don't provide IEqualityComparer, you likely don't need Union.
You can only union two lists at a time using Union() - but you can chain it to achieve what you want:
var resultList = list1.Union(list2).Union(list3).ToList();
You can try using the Union() linq extension method.
var finalSelectList = model.getFirstList().ToSelectList().Union(
model.getSecondList().ToSelectList().Union(
model.getThirdList().ToSelectList()))
Related
I have a List<Organisation> Organisations.
Each Organisation has a property List<int> Categories.
I also have a separate List<int> DisplayCategories
I want to create a new List<Organisation> called DisplayOrganisations.
DisplayOrganisations will contain Organisation's whos Categories appear in my List<int> DisplayCategories.
How can I achieve this using linq or lambda?
The following is incorrect:
DisplayOrganisations = (from o in Organisations
where o.Categories.Intersect(DisplayCategories.CategoryIds)
select o).ToList();
I get an error:
Cannot implicitly convert type
'System.Collections.Generic.IEnumerable' to 'bool'
I believe that this is because I am selecting Organisations who's sub list of Categories need to be compared to a separate list DisplayCategories.
Any ideas?
Sure intersect will not give a boolean. you may want to check if there is any elements exist in it use Any.
DisplayOrganisations = Organisations
.Where(o => o.Categories.Intersect(DisplayCategories.CategoryIds)
.Any()).ToList();
Or better approach.
DisplayOrganisations = Organisations.Where(o => o.Categories
.Any(xDisplayCategories.CategoryIds.Contains)).ToList();
As you can see in the image Intersect uses hashset which is faster than second approach because Hashset has time complexity of O(1) for both adding and removing items. So in general Intersect is O(n+m). but the second approach using Any and Contains had time complexity of O(n^2) which could become much slower.Thanks to Dmitry Dovgopoly.
If you need only those Organisations where all elements are in CategoryIds list you can use mixture of Except() and Any() methods :
var DisplayOrganisations = Organisations.Where(o =>
!o.Categories.Except(DisplayCategories.CategoryIds).Any()).ToList();
If you just want to check that there is at least one id in the list of ids you can use .Any method :
var DisplayOrganisations = Organisations.Where(o => o.Categories
.Any(DisplayCategories.CategoryIds.Contains)).ToList();
With my two lists of objects, I want to keep the total set of unique items based on a string key, where any collisions come from the first list, and any misses come from the second. Stated differently, I want to ignore any items in the first list that are not in the second list, but I want to keep all items that do exist in the second list as well as any remaining items from the second list.
What's the best way to do this?
Edit: This problem is more subtle than a simple union. A union will join the distinct items from two lists. In the case of a collision it takes the item from the outer list.
In my case, I have some items in List1 that I don't want to keep because they don't exist in List2, while I do want to keep all items from list 2.
Is there a cleaner / shorter way to do the below?
var remaining = allowedItems.Except(recentItems)
var allowedRecentItems = recentItems.Intersect(allowedItems)
var result = allowedRecentItems.Concat(remaining);
Try this:
var resultlist = list1.Union(list2);
var list1 = new List<string>{"A", "B", "C"};
var list2 = new List<string>{"B", "C", "D"};
var list = list1.Union(list2);
If I understood it correctly - You should keep the second list only. By that your both conditions are fulfilled
I want to ignore any items in the first list that are not in the second list
off-course if you keep the second list only then all the items in the first list which are not present in the second list will automatically be ignored.
I want to keep all items that do exist in the second list as well as any remaining items from the second list
On the other hand, the items present in both of the lists will automatically be selected including those which are only present in the second list.
If that's not what you want then you should check List.Distinct(), List.Except() and List.Union() extension methods.
Using the second list just do the trick. Directly translating your your requirements produces:
list1.Intersect(list2).Union(list2) which results list2
I have 2 separate collections.
IQueryable<string> customers;
IQueryable<string> customersPhone
Currently, this is the code I am using to join one with the other
IEnumerable<string> union = customers.Union(customersPhone);
The problem is that when I have multiple like records in the customers collection, the union is causing only a single record to be returned. I need to return all, regardless of duplicates, and join them with the customersPhone collection.
Is this possible? Does that make sense?
Thanks!
Kevin
You're looking for Concat(), which preserves duplicates.
you could try one of the 2 options below List one is customers in your case list2 would be customerPhone make the corrections to fit your Use Case
IQueryable customers;
IQueryable customersPhone
var list1 = list1.Concat(customers);
or
var list4 = list1.Union(customersPhone);
I have a very long list of Ids (integers) that represents all the items that are currently in my database:
var idList = GetAllIds();
I also have another huge generic list with items to add to the database:
List<T> itemsToAdd;
Now, I would like to remove all items from the generic list whose Id is already in the idList.
Currently idList is a simple array and I subtract the lists like this:
itemsToAdd.RemoveAll(e => idList.Contains(e.Id));
I am pretty sure that it could be a lot faster, so what datatypes should I use for both collections and what is the most efficient practice to subtract them?
Thank you!
LINQ could help:
itemsToAdd.Except(idList)
Your code is slow because List<T>.Contains is O(n). So your total cost is O(itemsToAdd.Count*idList.Count).
You can make idList into a HashSet<T> which has O(1) .Contains. Or just use the Linq .Except extension method which does it for you.
Note that .Except will also remove all duplicates from the left side. i.e. new int[]{1,1,2}.Except(new int[]{2}) will result in just {1} and the second 1 was removed. But I assume it's no problem in your case because IDs are typically unique.
Transform temporarily idList to an HashSet<T> and use the same method i.e.:
items.RemoveAll(e => idListHash.Contains(e.Id));
it should be much faster
Assuming the following premises are true:
idList and itemsToAdd may not contain duplicate values
you are using the .NET Framework 4.0
you could use a HashSet<T> this way:
var itemsToAddSet = new HashSet(itemsToAdd);
itemsToAddSet.ExceptWith(idList);
According to the documentation the ISet<T>.ExceptWith method is pretty efficient:
This method is an O(n) operation,
where n is the number of elements in
the other parameter.
In your case n is the number of items in idList.
You should use two HashSet<int>s.
Note that they're unique and unordered.
i have a collection
IEnumerable<Project>
and i want to do a filter based on project's Id property to included any id that is in a list:
List<int> Ids
what is the best way to do a where clause to check if a property is contained in a list.
var filteredProjectCollection = projectCollection.Where(p => Ids.Contains(p.id));
You may be able to get a more efficient implementation using the Except method:
var specialProjects = Ids.Select(id => new Project(id));
var filtered = projects.Except(specialProjects, comparer);
The tricky thing is that Except works with two collections of the same type - so you want to have two collections of projects. You can get that by creating new "dummy" projects and using comparer that compares projects just based on the ID.
Alternatively, you could use Except just on collections of IDs, but then you may need to lookup projects by the ID, which makes this approach less appealing.
var nonExcludedProjects = from p in allprojects where Ids.Contains(p => p.Id) select p;
If you're going to use one of the .Where(p=> list.Contains(p)) answers, you should consier first making a HashSet out of the list so that it doesn't have to do an O(n) search each time. This cuts running time from O(mn) to O(m+n).
I'm not sure that I understand your question but I'll have a shot.
If you have: IEnumerable enumerable,
and you want to filter it such that it only contians items that are also present in the list: List list,
then: IEnumerable final = enumerable.Where(e => list.Contains(e));