I have the following code:
var workOrderList = new List<WorkOrder>(
from index in Enumerable.Range(1, orders.Length)
select new WorkOrder
{
OrderID = orders[index - 1],
Status = status[random.Next(0,status.Length-1)],
TotalQuantity = random.Next(1, 5) * 8,
ScheduleCollection = new ObservableCollection<Schedule>
{
new Schedule
{
Color = colors[random.Next(0,colors.Length-1)],
Model = models[random.Next(0,models.Length-1)],
Status = status[random.Next(0,status.Length-1)],
TotalNumber = To be Updated bases on Total Quantity
}
}
Now I want to update Total Number by either dividing or subtracting value from TotalQuantity .
Use a let clause in your query to extract common expressions:
var workOrderList = new List<WorkOrder>(
from index in Enumerable.Range(1, orders.Length)
let totalQuantity = random.Next(1, 5) * 8
select new WorkOrder
{
OrderID = orders[index - 1],
Status = status[random.Next(0,status.Length-1)],
TotalQuantity = totalQuantity,
ScheduleCollection = new ObservableCollection<Schedule>
{
new Schedule
{
Color = colors[random.Next(0,colors.Length-1)],
Model = models[random.Next(0,models.Length-1)],
Status = status[random.Next(0,status.Length-1)],
TotalNumber = // Do something with totalQuantity
}
}
});
Related
How to group by then sum inside the list
below is my sample code:
List<BrandType> brandTypeList = new List<BrandType>();
BrandType brandTypeClass = new BrandType();
brandTypeClass.Amount = 100;
brandTypeClass.Count = 50;
brandTypeClass.Category = "Fish";
brandTypeList.Add(brandTypeClass);
BrandType brandTypeClass2 = new BrandType();
brandTypeClass2.Amount = 100;
brandTypeClass2.Count = 50;
brandTypeClass2.Category = "Fish";
brandTypeList.Add(brandTypeClass2);
BrandType brandTypeClass3 = new BrandType();
brandTypeClass3.Amount = 100;
brandTypeClass3.Count = 50;
brandTypeClass3.Category = "Pork";
brandTypeList.Add(brandTypeClass3);
brandTypeList.GroupBy(x => new { x.Category }).Select
(x => new { Category = x.Key.Category,
Amount = x.Sum(z => z.Amount),
Count = x.Sum(z => z.Count) });
Here's what it looks like
[0] {Amount = 100, Category = "Pork", Count = 50}
[1] {Amount = 100, Category = "Fish", Count = 50}
[2] {Amount = 100, Category = "Fish", Count = 50}
How can I SUM the amout and count then group by Category?
I want the result to be
Amount = 200, Category = "Fish", Count = 100
Amount = 100, Category = "Pork" Count = 50
The following code snippet will work for you:
var result = from brand in brandTypeList
group brand by brand.Category into grp
select new
{
Category = grp.Key,
Amount = grp.Sum(z => z.Amount),
Count = grp.Sum(z => z.Count)
};
This one also works fine:
var result = brandTypeList.GroupBy(x => x.Category).Select
(y => new {
Category = y.Key,
Amount = y.Sum(z => z.Amount),
Count = y.Sum(z => z.Count)
});
It turns out that your code also works fine, probably the problem is that you expect list to be modified inplace, but linq does not produce side effects and new IEnumerable will be created and you need to save results to variable.
Here's my code which works up to a point:
var Data = File.ReadAllLines(FilePath).Select(line => line.Split('\t')).ToArray();
int caseSwitch = 0;
if (radioButton1.Checked == true)
{
caseSwitch = 1;
}
else if (radioButton2.Checked == true)
{
caseSwitch = 2;
}
else if (radioButton3.Checked == true)
{
caseSwitch = 3;
}
var query = from x in Data
let sw = caseSwitch
select
sw == 1 ? new { Name = x[6], Age = x[2], Date = x[4], Score = x[7] }
: sw == 2 ? new { Name = x[9], Age = x[1], Date = x[0], Score = x[3] }
: sw == 3 ? new { Name = x[5], Age = x[8], Date = x[2], Score = x[1] }
: null;
It seems the code stops working when I have up to 8 case switch scenarios...the error I seem to get once I have 8 scenarios is "Index was outside the bounds of the array" whilst the ": null;" statement is highlighted in yellow. What am I doing wrong?
"Index was outside the bounds of the array" would indicate that you have a bad index value for x in one (or more) of your cases - the number of switch statements would not cause that error.
Post the line in your select that causes the error.
A better way to do this might be to have the query do everything but the select itself. You can then do your switch like this:
IQueryable<whatever> newQuery;
switch (caseSwitch)
{
case 1: newQuery = query.Select(i => new { Name = i[9], ... }); break;
case 2: newQuery = query.Select(i => new { Name = i[6], ... }); break;
}
Note that you can't use an anonymous type, but that shouldn't be a problem here. This way, you only send the query you actually want, rather than doing a case on the server.
You do not need a conditional statement there at all - since the structure of your query does not change, all you need is a table providing the indexes for Name, Age, Date, and Score columns:
class ColumnIndex {
int NameIndex {get;set;}
int AgeIndex {get;set;}
int DateIndex {get;set;}
int ScoreIndex {get;set;}
}
private static readonly ColumnIndex[] ColIndex = new[] {
new ColumnIndex {NameIndex = 6, AgeIndex = 2, DateIndex = 4, ScoreIndex = 7}
, new ColumnIndex {NameIndex = 9, AgeIndex = 1, DateIndex = 0, ScoreIndex = 3}
, new ColumnIndex {NameIndex = 5, AgeIndex = 8, DateIndex = 2, ScoreIndex = 1}
, ...
};
...
int caseSwitch = -1;
if (radioButton1.Checked == true)
{
caseSwitch = 0;
}
else if (radioButton2.Checked == true)
{
caseSwitch = 1;
}
else if (radioButton3.Checked == true)
{
caseSwitch = 2;
}
var query = from x in Data
select new {
Name = x[ColIndex[caseSwitch].NameIndex]
, Age = x[ColIndex[caseSwitch].AgeIndex]
, Date = x[ColIndex[caseSwitch].DateIndex]
, Score = x[ColIndex[caseSwitch].ScoreIndex]
};
(Not sure if I even need GroupBy)
My (simplified) tables:
Products (ProductID, Name, Code)
Invoices (InvoiceID, Number, IsPaid)
Invoices_Products (InvoiceID, ProductID, Quantity, Price) - the many-to-many linking table
I need to show a list of Invoices_Products of paid Invoices grouped by the Product Code which sums (Quantity*Price).
The code that I first use to get a collection that I can bind to the UI:
IEnumerable<Invoices_Products> invoices_products = db.Invoices_Products
.Where(ip => ip.Invoice.IsPaid).DistinctBy(m => m.Product.Code);
I then iterate through this to bind it to the UI:
List<BindableInvoiceProduct> bindableInvoiceProducts =
new List<BindableInvoiceProduct>();
foreach (var item in invoices_products)
{
decimal salesValue = db.Invoices_Products.Where(ip => ip.Invoice.IsPaid
&& ip.Product.Code == item.Product.Code).Sum(m => (m.Price * m.Quantity));
bindableInvoiceProducts.Add(new BindableInvoiceProduct()
{
A = item.A,
B = item.B,
SalesValue = salesValue.ToString()
});
}
(The DistinctBy method there is from morelinq)
Why does this not total correctly?
edit:
Some data:
Product - ProductID = 1, Name = 123, Code = A
Product - ProductID = 2, Name = 456, Code = A
Invoice - InvoiceID = 1, Number = INV123, IsPaid = True
Invoices_Products - InvoiceID = 1, ProductID = 1, Quantity = 10, Price = 100
Invoices_Products - InvoiceID = 1, ProductID = 2, Quantity = 10, Price = 200
Expected result:
Code = A, SalesValue = 3000
from invoice in invoices
where invoice.IsPaid
from xr in invoice.InvoiceProducts
group xr.Quantity * xr.Price by xr.Product.Code into g
select new {Code = g.Key, SalesValue = g.Sum()};
If you want per invoice, then:
from invoice in invoices
where invoice.IsPaid
from xr in invoice.InvoiceProducts
group xr.Quantity * xr.Price
by new {Code = xr.Product.Code, Invoice = invoice }
into g
select new {
Code = g.Key.Code,
Invoice = g.Key.Invoice,
SalesValue = g.Sum()};
Based on your description I would have written:
var bindableInvoiceProducts = db.Invoices_Products
.Where(ip => ip.Invoice.IsPaid)
.GroupBy(ip => ip.Product.Code,
(code, ips) => new BindableInvoiceProduct()
{
Code = code,
SalesValue = ips.Sum(ip => (ip.Price*ip.Quantity))
})
.ToList();
Is that, what you need? What is item.A and item.B in your code?
I have a table
ID|VALUE
VALUE is an integer field with possible values between 0 and 4. How can I query the count of each value?
Ideally the result should be an array with 6 elements, one for the count of each value and the last one is the total number of rows.
This simple program does just that:
class Record
{
public int Id { get; set; }
public int Value { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<Record> records = new List<Record>()
{
new Record() { Id = 1, Value = 0},
new Record() { Id = 2, Value = 1 },
new Record() { Id = 3, Value = 2 },
new Record() { Id = 4, Value = 3 },
new Record() { Id = 5, Value = 4 },
new Record() { Id = 6, Value = 2 },
new Record() { Id = 7, Value = 3 },
new Record() { Id = 8, Value = 1 },
new Record() { Id = 9, Value = 0 },
new Record() { Id = 10, Value = 4 }
};
var query = from r in records
group r by r.Value into g
select new {Count = g.Count(), Value = g.Key};
foreach (var v in query)
{
Console.WriteLine("Value = {0}, Count = {1}", v.Value, v.Count);
}
}
}
Output:
Value = 0, Count = 2
Value = 1, Count = 2
Value = 2, Count = 2
Value = 3, Count = 2
Value = 4, Count = 2
Slightly modified version to return an Array with only the count of values:
int[] valuesCounted = (from r in records
group r by r.Value
into g
select g.Count()).ToArray();
Adding the rows count in the end:
valuesCounted = valuesCounted.Concat(new[] { records.Count()}).ToArray();
Here is how you would get the number of rows for each value of VALUE, in order:
var counts =
from row in db.Table
group row by row.VALUE into rowsByValue
orderby rowsByValue.Key
select rowsByValue.Count();
To get the total number of rows in the table, you can add all of the counts together. You don't want the original sequence to be iterated twice, though; that would cause the query to be executed twice. Instead, you should make an intermediate list first:
var countsList = counts.ToList();
var countsWithTotal = countsList.Concat(new[] { countsList.Sum() });
I have a products sales table that looks like this:
saleDate prod qty
10/22/09 soap 10
09/22/09 pills 05
09/25/09 soap 06
09/25/09 pills 15
I need to make the SUM of each MONTH so the final table would look like this:
saleDate prod qty
10/09 soap 10
09/09 soap 06
09/09 pills 20
Can I do this with LINQ?
var products = new[] {
new {SaleDate = new DateTime(2009,10,22), Product = "Soap", Quantity = 10},
new {SaleDate = new DateTime(2009,09,22), Product = "Pills", Quantity = 5},
new {SaleDate = new DateTime(2009,09,25), Product = "Soap", Quantity = 6},
new {SaleDate = new DateTime(2009,09,25), Product = "Pills", Quantity = 15}
};
var summary = from p in products
let k = new
{
//try this if you need a date field
// p.SaleDate.Date.AddDays(-1 *p.SaleDate.Day - 1)
Month = p.SaleDate.ToString("MM/yy"),
Product = p.Product
}
group p by k into t
select new
{
Month = t.Key.Month,
Product = t.Key.Product,
Qty = t.Sum(p => p.Quantity)
};
foreach (var item in summary)
Console.WriteLine(item);
//{ Month = 10/09, Product = Soap, Qty = 10 }
//{ Month = 09/09, Product = Pills, Qty = 20 }
//{ Month = 09/09, Product = Soap, Qty = 6 }
var q = from s in sales
group s by new {saleDate = s.saleDate.ToString("MM/yy"), s.prod} into g
select new { g.Key.saleDate, g.Key.prod, qty = g.Sum(s => s.qty) };
class Program
{
static void Main(string[] args)
{
var sales = new List<Sale>();
sales.Add(new Sale() { Product = "soap", saleDate = new DateTime(2009, 10, 22), Quantity = 10});
sales.Add(new Sale() { Product = "soap", saleDate = new DateTime(2009, 9,22), Quantity = 6});
sales.Add(new Sale() { Product = "pills", saleDate = new DateTime(2009,9,25), Quantity = 15});
sales.Add(new Sale() { Product = "pills", saleDate = new DateTime(2009,9,25), Quantity = 5});
var q = from s in sales
group s by new { s.Product, s.saleDate.Month, s.saleDate.Year } into g
select new {Month = String.Format("{0:MM/yy}", new DateTime(g.Key.Year, g.Key.Month, 1)), product = g.Key.Product, quantity = g.Sum(o=>o.Quantity)};
}
}
class Sale
{
public DateTime saleDate { get; set; }
public int Quantity { get; set; }
public string Product { get; set; }
}
Sure.
It'll look like this:
var GroupedSales =
from p in products
group p by p.saleDate.Month into g
select new { saleMonth = g.saleDate.Month, QtySold = g.Sum(p => p.qty) };
See: http://msdn.microsoft.com/en-us/vcsharp/aa336747.aspx#sumGrouped
Also, note that I was operating under the assumption that your dataset only had 2009 data. If you want to group by month/year, you can use saleDate.ToString("yyyyMM") instead of saleDate.Month.