I have following LINQ query
var unallocatedOrders = (from orderLine in context.OrderLineItemDboes
where (orderLine.Status == unallocated || orderLine.Status == null)
&& orderLine.orderline.order.order_status_fk == verified
group orderLine
by new { orderLine.orderline.ol_id,orderLine.orderline.order.order_id }
into g
select new { OrderLineId = g.Key.ol_id, Count = g.Count(), OrderId = g.Key.order_id })
.ToList();
Above query giving me results in the following way
Order1 ol1 2
order1 ol2 3
order1 ol3 1
order2 ol1 1
order2 ol2 2
order3 ol1 4
order3 ol2 3
order3 ol3 2
I need to iterate through the above list based on order ids and need to fetch corresponding lines and quantity.
I need to get this line id and quantity to a Dictionary.
Can somebody suggest how can I get it done.
Thanks
Here's how you can select the items using GroupBy. (Your question doesn't really specify how you want to use the lines, so I just output them to the Debug console.)
// group by the OrderId
foreach (var group in unallocatedOrders.GroupBy(row => row.OrderId))
{
Debug.WriteLine(
// for each line, output "Order x has lines y1, y2, y3..."
string.Format("Order {0} has lines {1}",
// here the key is the OrderId
group.Key,
// comma-delimited output
string.Join(", ",
// select each value in the group, and output its OrderLineId, and quantity
group.Select(item =>
string.Format("{0} (quantity {1})", item.OrderLineId, item.Count)
)
)
)
);
}
You can get a dictionary lookup by using ToDictionary.
// two-level lookup: 1) OrderId 2) OrderLineId
var lookup = new Dictionary<int, Dictionary<int, long>>();
foreach (var group in unallocatedOrders.GroupBy(row => row.OrderId))
{
// add each order to the lookup
lookup.Add(group.Key, group.ToDictionary(
// key selector
keySelector: item => item.OrderLineId,
// value selector
elementSelector: item => item.Count()
));
}
Related
I have a requirement where I need to filter out the null values from a list, only if the null value appears after the first non-null value and before the last non-null value.
Product one = new Product { Name="A" Priority="1" Value=null };
Product two = new Product { Name="A" Priority="2" Value=null };
Product three = new Product { Name="A" Priority="3" Value="10" };
Product four = new Product { Name="A" Priority="4" Value=null };
Product five = new Product { Name="A" Priority="5" Value="20" };
Product six = new Product { Name="A" Priority="6" Value=null };
In the example, I need to first sort the list of products based on their priority and then check the first non-null value (ie., priority 3) and last non-null value (ie, priority 5), then get the list of all products with null values within priority 3 & 5. So, in our example only Product 4 with Priority 4 is the record I am looking for.
I got to the part of actually grouping them by products and sorting them by priority but stuck on how to proceed after that
from p in Products
group p by p.Product into grp
select new
{
Product = grp.Key
Values = grp.OrderBy(x => x.Priority)
}
Can someone point me as how to proceed? I am thinking I may to use the indexes to identify all the non-null and iterate through to get min and max Priority values and later query for all records with blank null values within the min/max priority.
It would be easier and more efficient if you determined which values are your start and stop points in the group and filter from there.
var query =
from product in Products
group product by product.Name into g
let ordered = g.OrderBy(p => p.Priority).ToList()
let firstIndex = ordered.FindIndex(p => p.Value != null)
let lastIndex = ordered.FindLastIndex(p => p.Value != null)
select new
{
Product = g.Key,
Values = ordered
.Skip(firstIndex + 1)
.Take(lastIndex - firstIndex - 1)
.Where(p => p.Value == null),
};
How about this (you can use .Select instead of .SelectMany to get separate groups for each product. .SelectMany combines all the valid result records into a single list):
Products
.GroupBy(p => p.Name)
.SelectMany (grp =>
grp.OrderBy(p => p.Priority) // sort by priority
.SkipWhile(p => p.Value == null) // skip null entries at beginning
.Reverse() // reverse
.SkipWhile(p => p.Value == null) // skip null entries at end
.Reverse() // reverse back to normal
.Where(p => p.Value == null) // then find null entries
);
Demo: http://ideone.com/2dU9L
I am trying to get all the rows in a table having the same value in a column. I got it working by using group by:
var groupedData = from row in Tab1Model.ExcelGridDataSource.AsEnumerable()
group row by row.Field<string>("A");
foreach (var group in groupedData)
{
if (group.Count() > 1)
{
//select from each group only the DataRows
//having a certain value in a second column
foreach (var dataRow in group)
{
multipleRowsList.Add(dataRow);
}
}
}
I would like to avoid calling foreach ,get only the groups having a count > 1 and then get ONLY
the DataRows that have a second column with a specific value. Thanks!
try this:
var query = from row in excelDataSource
group row by row.Field<string>("A") into g
select new { Value = g.Key, Rows = g };
var nonZeroRows= from q in query
where q.Rows.Count() > 0
select q.Rows;
// at this point you have an enumerable of enumerables of tablerows.
var list = nonZeroRows.Aggregate(Enumerable.Empty<TableRow>(),
(a, b) => a.Concat(b.Where(c => c.Something == true)); // your condition here
Thanks Atanamir! Here is the final code, just wonder if you have any better ways of doing it. the end goal of this is to flag one of the rows that is entered twice.
var groupedData = from row in Tab1Model.ExcelGridDataSource.AsEnumerable()
group row by row.Field<string>("A")
into g
select new {Value = g.Key, Rows = g};
var nonZeroesRows = from q in groupedData
where q.Rows.Count() > 1
select q.Rows;
//at this point you have an enumerable of enumerables of tables rows
var listRows = nonZeroesRows.Aggregate(Enumerable.Empty<DataRow>(),
(a, b) => a.Concat(b.Where(c => c.Field<bool>("Omit Row") == false)));
//grouped them again and get only the last row from the group wiht a count > 1
var doubleRows = from row in listRows
group row by row.Field<string>("A")
into g
where g.Count() > 1
select g.Last();
Or maybe better:
var groupedData = from row in Tab1Model.ExcelGridDataSource.AsEnumerable()
group row by row.Field<string>("A")
into g
where g.Count() > 1
select new {/*Value = g.Key,*/ Rows = g};
//at this point you have an enumerable of enumerables of tables rows
var listRows = groupedData.Aggregate(Enumerable.Empty<DataRow>(),
(a, b) => a.Concat(b.Rows.Where(c => c.Field<bool>("Omit Row") == false)));
//grouped them again and get only the last row from the group wiht a count > 1
var doubleRows = from row in listRows
group row by row.Field<string>("A")
into g
where g.Count() > 1
select g.Last();
I have divAssignments that has potential multiple rows by rNI, an official id, according to a compound key of Indictment and booking numbers.
rNI Booking Indictment
12345 954445 10 12345
12345 954445 10 12346
12345 954445 10 12347
So ID has a count of 3 for a single booking number for this rni.
I get lost attempting to generate a count and a group by booking Number:
var moreThen = from dA in divAssignments
select new { dA.rNI, IndictmentCount = dA.indictmentNumber.Count() };
Most of the examples are dealing with static int[] and don't seem to work in my case.
How do I get a group and then a count? If I could put in a having that would be fantastic.
from a t-sql POV I'd use this:
Select rni, bookingNumber, count(*) IndictmentCount
from divAssignments
group by rni, bookingNumber
having count(*) > 0
TIA
How about something like this:
var query = from item in divAssignments
group item by item.rNI into grouping
select new
{
Id = grouping.Key,
Count = grouping.Count()
}
If you're interested in grouping by both the rNI and the booking number, I would change it to this:
var query = from item in divAssignements
group item by new { item.rNI, a.Booking } into grouping
select new
{
Id = grouping.Key,
Count = grouping.Count
};
OR
var query = from item in divAssignments
group item by item into grouping
select new
{
Id = grouping.Key,
Count = grouping.Count()
}
and implement IEquatable on the divAssignment object to support equality comparison. The other option if you'd like is to write an IEqualityComparer instance to do the composite key comparison. Your query could then look like:
var query =
divAssignments
.GroupBy(i => i, new MyCustomEqualityComparer())
.Select(i => new { Key = i.Key, Count = i.Count());
var query =
from dA in divAssignments
group dA by new { dA.rNI, dA.bookingNumber };
foreach(var grp in query)
{
Console.WriteLine("rNI={0}, bookingNumber={1} => Count={2}", grp.Key.rNI, grp.Key.bookingNumber, grp.Count());
}
If you use a Grouping operator in Linq you will get what you need. The code:
var count = from a in divAssignments
group a by new { a.rNI, a.Booking } into b
select b;
will return a collection of IGrouping objects. This will give you the Key (in my example this will be an anonymous type with an rNI and a Booking property) and a collection of the divAssignments that match the key.
Using Method syntax (much easier to read in my opinion):
First group the records, then select a new result for each group that contains the count.
var groups = divAssignments.GroupBy(d => new { d.rNI, d.Booking });
groups.Select(g=> new { g.Key.rNI, g.Key.Booking, IndictmentCount = g.Count() });
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 am struggling once again so any help would be gratefully received.
I have the following LINQ that pulls back a list of data:
public static List<tblWeight> GetWeights(string memberid, string locationid, string buyer, string subcategory, string product)
{
MyEntity getweights = new MyEntity ();
var r = (from p in getweights.tblWeights
where p.MemberId == memberid &&
p.LocationId == locationid
select p);
if (buyer != "Not Specified")
r = r.Where(p => p.UnitUserField1 == buyer);
if (subcategory != "Not Specified")
r = r.Where(p => p.UnitUserField2 == subcategory);
if (product != "Not Specified")
r = r.Where(p => p.IDDesc == product);
return r.ToList();
}
Lovely!
What I would like to do now is based upon this result set and the unit IDs (IDDesc), I then go to tblPurchase, pull back a few columns from tblPurchases and group the columns.
So for example, we have tblWeight looking like so:
MemberID LocationID Buyer SubCategory IDDesc
1 1 Cat1 Sub1 ab
1 1 Cat1 Sub1 abc
1 1 Cat1 Sub2 abcd
The user makes a search for Sub1 in subcategory and the above LINQ does the trick and pulls back the first two rows from above. Fine.
What I need the LINQ to do now is to go to tblPurchases:
MemberID LocationID IDDesc SupplierID SupplierStatus
1 1 ab Sup1 Live
1 1 abc Sup1 Live
1 1 abcd Sup2 Dead
And then pull back the following result so it is joined on MemberID, LocationID and IDDesc but just selects tblPurchases.
Sup1 Live (or all columns in tblPurchases, just grouped/distinct)
I have tried to add in a join and on but no matter how many different variations, I still come across the red squiggle of doom!!!
If anyone can help, beer/kiss is on offer again.
The following LINQ query should do what you want:
var result = from w in tblWeight
where w.SubCategory == "Sub1"
join p in tblPurchases on
new { w.MemberID, w.LocationID, w.IDDesc } equals
new { p.MemberID, p.LocationID, p.IDDesc }
group p by new { p.SupplierID, p.SupplierStatus } into pg
select pg.Key;
The variable result is a list containing tuples of SupplierID and SupplierStatus.
If you also want to put the conditional parts in there, it gets a little more complicated. Here's how to do it:
var weights = from w in tblWeight
select w;
weights = weights.Where(w => w.SubCategory == "Sub1");
// You can add additional where clauses here.
// Now join with tblPurchases and group by SupplierID and SupplierStatus.
var result =
weights.Join(tblPurchases,
w => new { w.MemberID, w.LocationID, w.IDDesc },
p => new { p.MemberID, p.LocationID, p.IDDesc },
(w, p) => p)
.GroupBy(p => new { p.SupplierID, p.SupplierStatus },
(k, ps) => new
{
k.SupplierID,
k.SupplierStatus,
TotalQty = ps.Sum(p => p.PurchaseQty)
});