I have 1 very basic table which I need to query in order to get the amount (count) of rooms in each building code using a LinQ query.
So far i have this:
var myQuery =
from s in Locations
group s.Room by s.BldgCode into t
select t.Count();
myQuery.Dump();
with this output
Query (3 items)
2
4
7
How can I include the Building code details so I have an output like this:
BldgCode NoRooms (3 items)
A 2
B 4
C 7
foreach(var line in data.GroupBy(info => info.Room )
.Select(group => new {
BldgCode = group.Key,
NoRooms = group.Count()
})
{
Console.WriteLine("{0} {1}", line.BldgCode , line.NoRooms );
}
Related
I am trying to query a table with nested linq query. My query working but is too slow. I have almost 400k row. And this query work 10 seconds for 1000 rows. For 400k I think its about to 2 hours.
I have rows like this
StudentNumber - DepartmentID
n100 - 1
n100 - 1
n105 - 1
n105 - 2
n107 - 1
I want the students which have different department ID. My results looks like this.
StudentID - List
n105 - 1 2
And my query provides it. But slowly.
var sorgu = (from yok in YOKAktarim
group yok by yok.StudentID into g
select new {
g.Key,
liste=(from birim in YOKAktarim where birim.StudentID == g.Key select new { birim.DepartmentID }).ToList().GroupBy (x => x.DepartmentID).Count()>1 ? (from birim in YOKAktarim where birim.StudentID == g.Key select new { birim.DepartmentID }).GroupBy(x => x.DepartmentID).Select(x => x.Key).ToList() : null,
}).Take(1000).ToList();
Console.WriteLine(sorgu.Where (s => s.liste != null).OrderBy (s => s.Key));
I wrote this query with linqpad C# statement.
For 400K records you should be able to return the student ids and department ids into an in-memory list.
var list1 = (from r in YOKAktarim
group r by new { r.StudentID, r.DepartmentID} into g
select g.Key
).ToList();
Once you have this list, you should be able to group by StudentID and select those students who have more than one record.
var list2 = (from r in list1 group r by r.StudentID into g
where g.Count() > 1
select new
{
StudentID = g.Key,
Departments = g.Select(a => a.DepartmentID).ToList()
}
).ToList();
This should be faster as it only hits the sql database once, rather than hundreds of thousands of times.
You're iterating your source collection (YOKAktarim) three times, which makes your query *O(n^3)` query. It's going to be slow.
Instead of going back to source collection to get content of the group you can simply iterate over g.
var sorgu = (from yok in YOKAktarim
group yok by yok.StudentID into g
select new {
g.Key,
liste = from birim in g select new { birim.DepartmentID }).ToList().GroupBy (x => x.DepartmentID).Count()>1 ? (from birim in g select new { birim.DepartmentID }).GroupBy(x => x.DepartmentID).Select(x => x.Key).ToList() : null,
}).Take(1000).ToList();
However, that's still not optimal, because you're doing a lot of redundant subgrouping. Your query is pretty much equivalent to:
from yok in YOKAktarim
group yok by yok.StudentID into g
let departments = g.Select(g => g.DepartmentID).Distinct().ToList()
where departments.Count() > 1
select new {
g.Key,
liste = departments
}).Take(1000).ToList();
I can't speak for the correctness of that monster, but simply removing all ToList() calls except the outermost one will fix your issue.
I need to return all records (items) that has a part (X) so I can use that in a group or .GroupBy afterwards
Using this summary data:
ItemName PartName
1 A
1 B
2 A
3 C
So Item1 has two parts (A,B), etc...
I need a LINQ query that will
- find all items that have part A (i.e items 1 and 2)
- return all rows for all these items
1 A
1 B
2 A
Notice that the end result returned the row (1 B) because Item1 has PartA and so I need to get back all rows for Item1.
I was looking at something like:
let items = from data in summary where data.PartName == A select new { data.ItemName } // to get all the items I need
But then, now that I have that list I need to use it to get all the rows for all items listed, and I can't seem to figure it out ...
Actual Source Code (for reference):
NOTE:
Recipe = ITEM
Ingredient = PART
(I was just trying to make it simpler)
ViewFullRecipeGrouping = (
from data in ViewRecipeSummary
group data by data.RecipeName into recipeGroup
let fullIngredientGroups = recipeGroup.GroupBy(x => x.IngredientName)
select new ViewFullRecipe()
{
RecipeName = recipeGroup.Key,
RecipeIngredients = (
from ingredientGroup in fullIngredientGroups
select new GroupIngredient()
{
IngredientName = ingredientGroup.Key
}
).ToList(),
ViewGroupRecipes = (
from data in ViewRecipeSummary
// this is where I am looking to add the new logic to define something I can then use within the next select statement that has the right data based on the information I got earlier in this query.
let a = ViewRecipeSummary.GroupBy(x => x.RecipeName)
.Where(g => g.Any(x => x.IngredientName == recipeGroup.Key))
.Select(g => new ViewRecipe()
{
RecipeName = g.Key,
IngredientName = g.Select(x => x.IngredientName)
})
select new GroupRecipe()
{
// use the new stuff here
}).ToList(),
}).ToList();
Any help would be much appreciated.
Thanks,
I believe this does what you want:
var data = /* enumerable containing rows in your table */;
var part = "X";
var items = new HashSet<int>(data
.Where(x => x.PartName == part)
.Select(x => x.ItemName));
var query = data.Where(x => items.Contains(x.ItemName));
If I understand your comment at the end, I believe this also does what you want:
var query = data
.GroupBy(x => x.ItemName)
.Where(g => g.Any(x => x.PartName == part))
.Select(g => new
{
ItemName = g.Key,
PartNames = g.Select(x => x.PartName)
});
I've got a class like the following:
public class Invoice
{
public int InvoiceId {get;set;}
public int VersionId {get;set;}
}
Each time an Invoice is modified, the VersionId gets incremented, but the InvoiceId remains the same. So given an IEnumerable<Invoice> which has the following results:
InvoiceId VersionId
1 1
1 2
1 3
2 1
2 2
How can I get just the results:
InvoiceId VersionId
1 3
2 2
I.e. I want just the Invoices from the results which have the latest VersionId. I can easily do this in T-SQL, but cannot for the life of me work out the correct LINQ syntax. I'm using Entity Framework 4 Code First.
Order by the VersionId, group them by InvoiceId, then take the first result of each group. Try this:
var query = list.OrderByDescending(i => i.VersionId)
.GroupBy(i => i.InvoiceId)
.Select(g => g.First());
EDIT: how about this approach using Max?
var query = list.GroupBy(i => i.InvoiceId)
.Select(g => g.Single(i => i.VersionId == g.Max(o => o.VersionId)));
Try using FirstOrDefault or SingleOrDefault in place of Single as well... it would give the same result although Single shows the intention better.
EDIT: I've tested both these queries with LINQ to Entities. They seem to work, so perhaps the issue is something else?
Option 1:
var latestInvoices = invoices.GroupBy(i => i.InvoiceId)
.Select(group => group.OrderByDescending(i => i.VersionId)
.FirstOrDefault());
EDIT: Changed 'Last' to 'FirstOrDefault', LINQ to Entities has issues with the 'Last' query operator.
Option 2:
var invoices = from invoice in dc.Invoices
group invoice by invoice.InvoiceId into invoiceGroup
let maxVersion = invoiceGroup.Max(i => i.VersionId)
from candidate in invoiceGroup
where candidate.VersionId == maxVersion
select candidate;
My version:
var h = from i in Invoices
group i.VersionId by i.InvoiceId into grouping
select new {InvoiceId = grouping.Key, VersionId = grouping.Max()};
Update
As was mentioned by Ahmad in the comments, the above query will return a projection. The version below will return a IQueryable<Invoice>. I use composition to build the query because I think it is more clear.
var maxVersions = from i in Invoices
group i.VersionId by i.InvoiceId into grouping
select new {InvoiceId = grouping.Key,
VersionId = grouping.Max()};
var latestInvoices = from i in Invoices
join m in maxVersions
on new {i.InvoiceId, i.VersionId} equals
new {m.InvoiceId, m.VersionId}
select i;
I have the following LINQ conditional where clause query that produces a result of weights:
From this, I'd like to take the result set and join on another table, tblPurchases
var result = weights.Join(getsuppliersproducts.tblPurchases,
w => new { w.MemberId, w.MemberName, w.LocationId, w.UnitId },
p => new { p.MemberId, p.MemberName, p.LocationId, p.UnitId },
(w, p) => p);
In this second table, I have two columns I would like to perform an aggreagte function on, a sum on PurchaseQuantity and a count of UnitID.
So in its raw format, tblPurchases would look like so:
MemberID LocationID UnitId SupplierID SupplierStatus Purchases
1 1 ab Sup1 Live 10
1 1 abc Sup1 Live 10
1 1 abcd Sup2 Dead 50
From my results data set, I would like the output to look like so:
MemberID LocationID SupplierID SupplierStatus UnitIdCount Total Purchases
1 1 Sup1 Live 2 50
Also, with these amendments, can I still return this to a List?
How do I implement this using LINQ? I have tried, and failed miserably.
(To those who have seen my previous posts, I'm trying to cover all angles so I can fully understand the concept of what is going on in both SQL and LINQ)
That query will return an IEnumerable where each of the Purchases matches the MemberId, MemberName, LocationId and UnitId in the original Weights query. You can only easily do one aggregate at a time, so
var result = weights.Join(getsuppliersproducts.tblPurchases,
w => new { w.MemberId, w.MemberName, w.LocationId, w.UnitId },
p => new { p.MemberId, p.MemberName, p.LocationId, p.UnitId },
(w, p) => p).ToList();
Int32 count = result.Count();
Double quantity = result.Sum(p => p.PurchaseQuantity);
Is that what you're trying to do?
EDIT, after your reply of I would like to reutrn a list of tblPurchases with two new columns, the sum of Purchase Quantity and count of unit ID.
This gives a flat output:
var query = Weights.GroupJoin(
Purchases,
w => new {w.MemberId, w.LocationId},
p => new {p.MemberId, p.LocationId},
(w,p) => new {w.MemberId, w.LocationId, Count = p.Count(), Sum = p.Sum(x => x.Purchases)} );
Note that at the point we do the (w, p) => new {} that w is a single Weight and p is a list of Purchases matching that weight, so you can still keep all of teh (hierarchical) data:
var query = Weights.GroupJoin(
Purchases,
w => new {w.MemberId, w.LocationId},
p => new {p.MemberId, p.LocationId},
(w,p) => new {w.MemberId, w.LocationId, Count = p.Count(), Sum = p.Sum(x => x.Purchases), Purchases = p} );
I'm quite new to LINQ.
Suppose that I had the following table:
Incident
ID DeviceID Time Info
1 1 5/2/2009 d
2 2 5/3/2009 c
3 2 5/4/2009 b
4 1 5/5/2009 a
In LINQ, how could I write a query that finds the most recent and distinct (on Device ID) set of incidents? The result I'd like is this:
ID DeviceID Time Info
3 2 5/4/2009 b
4 1 5/5/2009 a
Do you have to create an IEqualityComparer to do this?
You can get the most recent incidents for each device (this is how I understood your question) with:
var query =
incidents.GroupBy(incident => incident.DeviceID)
.Select(g => g.OrderByDescending(incident => incident.Time).First())
.OrderBy(i => i.Time); // only add if you need results sorted
int filterDeviceID = 10;
var incidents = (from incident in incidentlist
where incident.DeviceID == filterDeviceID
select incident).Distinct().OrderBy( x => x.Time);