I have a method that works perfectly well and does what it's supposed to, albeit a little slow (30 - 40 seconds). I would like to be able to speed it up or at least make it more efficient, any ideas please?
The purpose is to generate a list of which customers are buying the top requested (topN) lines from a supplier. The first part gets a list of products from the requested supplier, the second part works out which products are the best selling by distribution and then sales and then adds those products to an array and they form the column names for the datatable. The last part loops all of the customer accounts and puts yes or no in the column if they have bought it in the last 3 months. I hope that makes sense.
private void CustomersBuyingRange(string supplier, int topN)
{
// Get a list of products from a supplier.
string[] products = productDetails
.Where(x => x.SupplierID == supplier.ToUpper())
.Select(x => x.ProductCode).ToArray();
// Rank the products by distribution and then by sales,
// then add the required amount to an array.
string[] topSellers = detailedOrderLines
.Where(x => products.Contains(x.ProductCode))
.GroupBy(x => x.ProductCode)
.Select(x => new
{
x.FirstOrDefault().ProductCode,
DeliveredQty = x.Sum(p => p.DeliveredQty),
Distribution = x.Select(c => c.CustomerID).Distinct().Count()
})
.OrderByDescending(x => x.Distribution)
.ThenByDescending(x => x.DeliveredQty)
.Take(topN)
.Select(a => a.ProductCode).ToArray();
DataTable table = new DataTable("Customers");
table.Columns.Add("CustomerID", typeof(string));
table.Columns.Add("Customer", typeof(string));
table.Columns.Add("AccountManager", typeof(string));
// Add the columns with the products.
foreach (string product in topSellers)
{
table.Columns.Add(product, typeof(string));
}
// We only want customers that have had an order in the last 3 months.
var customers = customerDetails
.Where(x => x.LastInvoiceDate > DateTime.Now.AddMonths(-3).Date)
.OrderBy(x => x.CustomerName)
.ToList();
foreach (var customer in customers)
{
DataRow row = table.NewRow();
row["CustomerID"] = customer.CustomerID;
row["Customer"] = customer.CustomerName;
row["AccountManager"] = customer.AccountManager;
for (int i = 0; i < topN; i++)
{
row[topSellers[i]] = detailedOrderLines
.Any(x => x.CustomerID == customer.CustomerID &&
x.ProductCode == topSellers[i] &&
x.InvoiceDate > DateTime.Now.AddMonths(-3).Date
) ? "Yes" : "No";
}
table.Rows.Add(row);
}
Export.ExportToExcel(table, true);
}
There are roughly 3000 customers.
Any advise would be greatly appreciated.
productDetails
,detailedOrderLines
andcustomerDetails
and what type of objects do they contain and how do you instantiate them? \$\endgroup\$