My datatable contains a large number of empty rows that are deleted. I'm using the following code to split the table into several new tables based on the value of Printers, however I need to add contingency for those deleted rows. How can I add this contingency within the following statement?
List<DataTable> dtCollection = dt.AsEnumerable()
.GroupBy(row => row.Field<string>("Printers"))
.Select(g => g.CopyToDataTable())
.ToList();`
My theory is that I should be able to create some sort of bool within GroupBy, but I'm not sure how to approach this.
If you want to filter out those rows which were deleted, then you can use simple Where statement which checks state of a row:
List<DataTable> dtCollection = dt.AsEnumerable()
.Where(row => row.RowState != DataRowState.Deleted)
.GroupBy(row => row.Field<string>("Printers"))
.Select(g => g.CopyToDataTable())
.ToList();
Related
I have a datatable that I am returning to the UI layer.
I have multiple tables with the same FirstId value. A few may have a value in teh FieldOne. I only want to group the records where FieldOne is null.
I tried the following LINQ statement with .Where and .Groupby but the .Where removes all the records with values in FieldOne and then do the GroupBy. In the UI grid, the records with FieldOne values are missing. I want to only group the records with empty FieldOne values and still have the records with FieldOne values. Thanks.
MyDataAsEnumerable()
.Where(f => f.Field<string>("FieldOne") == null)
.GroupBy(r => new { pp1 = r.Field<int>("FirstId") })
.Select(g => g.First())
.CopyToDataTable();
You could make an artifical grouping key:
.GroupBy(
r => new { pp1 = f.Field<string>("FieldOne") == null ? -1 : r.Field<int>("FirstId") })
Here, I used -1 as a hack to create a separate group. Make sure this int value is not in use. You could also solve this precisely but hopefully this is OK.
I have a list that is getting its values from the database and then this is converted to a datatable, but before doing that i want to apply groupby on the list and get all the columns instead of just a key and a value. After a new list is created using groupby datatable does not show all the columns instead it has only two columns which says capacity and count.
var groupedResults = Results.GroupBy(x => x.PROJECT_ID)
.Select(y => y.ToList())
.ToList();
Results is a list which contains around 14 columns or keys in this case with all project related properties project name, id etc. When I use Results and convert that to datatable I do not have any issue but when I use groupedResults list as shown above and convert that to a datatable it does not have all the 14 columns and an exception is raised as column not found. Is there a way to select all the keys as in original list.
Thank you
Have you tried wwith something like:
var groupedResults = Results.GroupBy(x => new {x.PROJECT_ID, obj = x})
.Select(y => y.Key.obj.ToList())
.ToList();
Try something like this
var e = Results.GroupBy(x => x.PROJECT_ID) .Select(y =>new { ProjectId = y.Key,
Count=y.Count()})
.Join(Results,x=>x.ProjectId,y=>y.PROJECT_ID,(x1,y1) => new
{x1.ProjectId,x1.Count,y1.Col1,y1.Col2 /* Add all columns you need */} )
.ToList();
I have a problem getting last row in a each group. I am using Linq query to retrieve the groups.
Here is my LINQ query.
return View(db.tblMsgs.OrderByDescending(a => a.Id)
.GroupBy(a => new { a.Sender, a.Receiver }).Select(x => x.FirstOrDefault())
.Where(a => a.Receiver == username).ToList());
using FirstOfDefault() I am getting first row in a group.
Using LastOrDefault() I am getting run time exception.
That's what I run into too, in some time now.
After a little bit of research I found out that only way that works as it must is to reverse the list that you want the get the last item of and get the first item.
The reason behind this is that SQL languages does not have a statement as SELECT BOTTOM but SELECT TOP. Hence our LastOrDefault query could not be translated into SQL.
The possible way of doing so is to OrderByDescending method.
return View(db.tblMsgs.OrderByDescending(a => a.Id)
.GroupBy(a => new { a.Sender, a.Receiver }).Select(x => x.OrderByDescending(y => y.SomeAttribute).FirstOrDefault())
.Where(a => a.Receiver == username).ToList());
Edit:
Only thing you should be choosy about is the column to order by. It can be the id field if it is an auto incremented number value, or an add date of the row(better be generated by server or it can cause problems).
I have a List of Type X. This contains fields and I need to return only unique records from the list. I need to use one of the field/property (OIndex) that contains a timestamp and filter it using that property. List is like this:
> 2c55-Checked-branchDeb-20160501121315-05
> 2c60-Checked-branchDeb-20160506121315-06
> 2c55-Checked-branchDeb-20160601121315-07
> 2c55-Checked-branchDeb-20160601141315-07
> 2c60-Checked-branchDeb-20160720121315-08
In the example above the last field is the recordId so we have a duplicate record of "07". The timestamp is field four. So I want to get the all the records except that 3rd which is a duplicate. The latest version of record "07" is the fourth line.
I started doing the code but struggling. So far:
List<X> originalRecords = GetSomeMethod(); //this method returns our list above
var duplicateKeys = originalRecords.GroupBy(x => x.Record) //x.Record is the record as shown above "05", "06" etc
.Where(g => g.Count() > 1)
.Select(y => y.Key);
What do I do now? Now that I have the duplicate keys.
I think I need to go through the OriginalRecords list again and see if it contains the duplicate key.
And then use substring on the datetime. Store this somewhere and then remove the record which is not the latest. And save the original records with the filter. Thanks
You don't need to find duplicate keys explicitly, you could simply select first from each group:
var res == originalRecords
.GroupBy(x => x.RecordId)
.Select(g => g.OrderByDescending(x => x.DateTimeField).First());
There is no field for datetimefield as in your code. I simply have a string field which contains the datetime together with other data. The record however has a Record Id field.
You can split your records on a dash, grab the date-time portion, and sort on it. Your date/time is in a format that lets you sort lexicographically, so you can skip parsing the date.
Assuming that there are no dashes, and that all strings are formatted in the same way, x.TextString.Split('-')[3] expression will give you the timestamp portion of your record:
var res == originalRecords
.GroupBy(x => x.RecordId)
.Select(g => g.OrderByDescending(x => x.TextString.Split('-')[3]).First());
This should solve your problem:
List<X> originalRecords = GetSomeMethod();
Dictionary<int, X> records = new Dictionary<int, X>();
foreach (X record in originalRecords) {
if(records[record.recordId] != null) {
if(records[record.recordId].stamp < record.stamp){
records[record.recordId] = record;
}
}
else {
records[record.recordId] = record;
}
}
Your answer are records.Values
Hope it helps
I'm pulling items from a table that i'm including another table.
When including, there is likely multiple rows belonging to that item in the included table but I only want to include the row that contains the max value of a column.
items.AddRange(db.AuctionItems
.Include(f => f.AuctionBids.Max().Bid)
.OrderBy(x => x.Item));
Also tried
items.AddRange(db.AuctionItems
.Include(f => f.AuctionBids.Max(y => y.Bid))
.OrderBy(x => x.Item));
Error
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
Added info
Table AuctionItems
ID
Name
.....
Table AuctionBids
ID
ItemID
Bid
....
So I want to pull all items and include only the row that contains the highest bid for that item.
You may do the following:
db.AuctionItems
.Select(s => new{ai = s, bid = s.AuctionBids.OrderByDescending(o => o.Bid).FirstOrDefault()})
.AsEnumerable()
.Select(s => s.ai)
Using this approach you are loading only required AuctionBids into context and EF will do the mapping to appropriate AuctionItems for you.