I'm currently working my way through the learning curve that is LINQ and I could really use some assistance. I don't know if what I want is possible, but if I had to wager, I bet it is.
I currently have a list of objects called _tables and each of these objects has within it another list of objects exposed through the property, "Indexes". Essentially, I'd like to end up with one List that contains all the Indexes from all of the _tables.
Here's what I have so far:
var indexes = from TableInfo tab
in _tables
where tab.Indexes.Count > 0
select tab.Indexes;
Unfortunately, this seems to be giving me another List of Lists, but only where the Indexes List contains more than one value... Is there some way to get all of these lists together without loops?
You want to use the SelectMany extension method.
_tables.SelectMany(t => t.Indexes)
In addition to tbischel's answer, the query expression version of what you're going for is below.
var indexes = from TableInfo tab in _tables
from index in tab.Indexes
select index;
You don't need the where clause and you also shouldn't need to tell it what tab is
And you will need to use SelectMany
var indexes = (from tab in _tables).SelectMany(t => t.Indexes)
Or you could do it like this
var indexes = from tab in _tables
from t in tab.Indexes
select t;
That should be a little more familiar syntaz
var rows = from item in table select item;
Related
Currently I'm working on a project using LinqtoSql and I would like to get an simpler solution for my current problem.
Example:
Lets say I got a table named Example with three rows (with values 1,2,4)
Now in code(c#) I got these values as a list of Integer(lets name it lstExisting)
Now in my method I got another List of Integer ( say lstCurrent) with Integers values (1,2,3)
Now I want to compare the both the list and find the difference of integers and update the database, so according to my example a new row with value 3 should be added and the existing row with value 4 should be deleted.
PS:(the integer values will be always unique and will be 1,2,3,4)
Linq solutions will be preferable but I don't mind other easier solutions.
Thanks
You need to find new items and to be deleted items using Except like:
var newItems = lstCurrent.Except(lstExisting).ToList();
var toBeDeletedItems = lstExisting.Except(lstCurrent).ToList();
Later you can iterate each list and Add/Delete accordingly.
Try using Contains(). With having two lists, you can write something like this. What this does is it iterates over each item in your methods list and checks the original to see if its there.
var lstExisting = getExistingList();
var lstCurrent = getCurrentList();
foreach(var currentInt in lstCurrent)
{
if(!lstExisting.Contains(currentInt))
{
//insert currentInt
}
I have a collection of ID numbers that I wish to return some object for, I'm doing it by using a linq statement with a where that's using a contains statement:
var recentCats = (from i in EntityCache.Default.GetAll<Categories>()
where WebProfile.Current.RecentlyCreatedCategories.Contains(i.Id)
&& BoundCategory.ParentItemClass.Id.Equals(i.ParentItemClass.Id)
select new CategoryInfo()
{
Category = i,
ClassId = i.ParentItemClass.Id,
ClassImage = NamedResourceManager.GetResourceBinary(i.ParentItemClass.NameResourceId)
});
This works perfectly fine, except that I want to keep the order of items in the returned collection the same as they were in the list that goes in. So for example if I had a list of IDs: 14, 603, 388, I want the objects that come back to be in the same order, not the order that they're returned by the cache. Is there any way in entity framework to do this, or any way to do it that doesn't involve me writing a foreach loop?
Thanks
The Where Linq extension as with most extensions maintains the original order of the list.
Do LINQ's Enumerable Methods Maintain Relative Order of Elements?
As long as you do not explicitly reorder or use an operator that naturally would reorder the original list's order should be maintained. Obviously reordering the list for a where statement would be unneeded overhead.
The reason the information above does not apply to this question is in the comments bellow.
I would suggest changing the output of the select to be a key/value pair, where the key is the index of the Id in your list, and the value is your new object, then orderBy the key on the resulting set, and select the value.
For anyone interested, I was able to get them to come out in the same order as the list by joining them, as mentioned by Ray in the comments above.
var recentCats = (from i in WebProfile.Current.RecentlyCreatedCategories
join b in allCats
on i equals b.Id
where BoundCategory.ParentItemClass.Id.Equals(b.ParentItemClass.Id)
select ...
Thanks again for all your help & answers.
I've been looking for something like that for days. I'm trying to remove all the elements from a bigger list A according to a list B.
Suppose that I got a general list with 100 elements with differents IDS and I get another list with specific elements with just 10 records. I need remove all the elements from the first list that doesn't exists inside the second list.
I'll try to show the code that I actually don't know how it didnt works.
List<Obj> listA = new List<Obj>();
List<Obj> listB = new List<Obj>();
//here I load my first list with many elements
//here I load my second list with some specific elements
listA.RemoveAll(x => !listB.Contains(x));
I don't know why but it's not working. If I try this example with a List<int> type, it works nicely but I'd like to do that with my object. This object got an ID but I don't know how to use this ID inside the LINQ sentence.
You need to compare the IDs:
listA.RemoveAll(x => !listB.Any(y => y.ID == x.ID));
List(T).RemoveAll
I believe you can use the Except Extension to do this.
var result = listA.Except(listB)
Reference: http://www.dotnetperls.com/except
If you want to remove a list of objects (listB) from another list (listA) use:
listA = listA.Except(listB).ToList()
Remember to use ToList() to convert IEnumerable<Obj> to List<Obj>.
who ever is viewing this now.I think var result = listA.Intersect(listB) will give the result for common values in the both the list.
According to the documentation on MSDN ( http://msdn.microsoft.com/en-us/library/bhkz42b3.aspx ), contains uses the default Equality comparer to determine equality, so you could use IEquatable's Equals method on your Obj class to make it work. HiperiX mentions the ref comparison above.
How to add the IEquateable interface: http://msdn.microsoft.com/en-us/library/ms131190.aspx
I have list of objects I need to sort based on some of their properties. This works fine to sort it by one field:
reportDataRows.Sort((x, y) => x["Comment1"].CompareTo(y["Comment1"]));
foreach (var row in reportDataRows) {
...
}
I see lots of examples on here that do this with only one field. But how do I sort by one field, then another? Or how about a list of many fields? It seems like using LINQ orderby thenby would be best, but I don't know enough about it to know how use it.
For the parameters, something like this that supports any number of fields to sort by would be nice:
var sortBy = new List<string>(){"Comment1","Time"};
I don't want to be writing code to do this in every one of my apps. I plan on moving this sort code to the class that holds the data so that it can do more advanced things like using a list of parameters and implicitly recognizing that the field is a date and sorting it as a date instead of a string. The reportDataRow object contains fields with this information, so I don't have to do any messy checks to find out if the field is supposed to be a date.
Yes, I think it makes more sense to use OrderBy and ThenBy:
foreach (var row in reportDataRows.OrderBy(x => x["Comment1"]).ThenBy(x => x["Comment2"])
{
...
}
This assumes the other thing you want to order by is "Comment2".
Try this:
reportDataRows.Sort((x, y) =>
{
var compare = x["Comment1"].CompareTo(y["Comment1"]);
if(compare != 0)
return compare;
return x["Comment2"].CompareTo(y["Comment2"]);
});
You may want to look at this previous answer where I posted an extension method which handles multiple order by's in LINQ. This allows this sort of syntax:
myList.OrderByMany(x => x.Field1, x => x.Field2);
Look at the example for ThenBy on msdn.
If you're comparing your own objects, then you can implement the IComparable interface.
Otherwise, you can use the IComparer interface.
Using LINQ method syntax:
var sortedRows = reportDataRows.OrderBy(r => r["Comment1"])
.ThenBy(r => r["AnotherField"];
foreach (var row in sortedRows) {
...
}
And even more readable using query comprehension syntax:
var sortedRows = from r in reportDataRows
orderby r["Comment1"], r["Comment2"]
select r;
foreach (var row in sortedRows) {
...
}
You got it. Enumerable.OrderBy().ThenBy() is your ticket. It works exactly like it looks; elements are sorted by each projection, with ties decided by comparing the next projection. You can chain as many ThenBys as you want, and there are also OrderByDesc and ThenByDesc methods that will sort that projection in descending order.
As Albin has pointed out, An OrderBy chain does not touch the original list unless you assign the result of the ordering back to the original variable, like this:
reportDataRows = reportDataRows.OrderBy(x=>x.Comment1).ThenBy(x=>x.Comment2).ToList();
As a rule, OrderBy will perform slightly slower than List.Sort(); the algorithm is designed to work on any IEnumerable series of elements, so in order to sort (which requires knowing every element of the series) it slurps its entire source enumerable into a new array. However, OrderBy has a distinct advantage over Sort in that it is a "stable" sort; elements that are exactly equal to each other will retain their "relative order" in the sorted enumerable (the first of the two that you;d encounter when iterating through the unsorted list will be the first of the two encountered when iterating through the sorted list).
I have two lists and I want to select items that are not in the second list from the first list. I have no Linq experience to I think this should be a good way to start learning.
You can use Except for this:
var query = list1.Except(list2);