I have the 3 classes Item, Order and Management.
Order has an array with ordered Items, Management has a List of different Orders. How can I display the number of ordered items for all PurchaseOrders with the given name?
For example: Item1 is ordered 2 times with quantity = 5 and 2 times with quantity = 7, so the total number is 2*5+2*7=24.
I can solve the task, but only Linq should be used without loops, etc.
class MainClass
{
public static void Main(string[] args)
{
Management Management = new Management();
Management.PrintQuantityForSingleItem("Item1");
}
}
class Item
{
public string Name { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
public Item(string Name, decimal Price, int Quantity)
{
this.Name = Name;
this.Price = Price;
this.Quantity = Quantity;
}
}
class Order
{
public int Id { get; set; }
public Item[] Items { get; set; }
public Order(int Id, Item[] Items)
{
this.Id = Id;
this.Items = Items;
}
}
class Management
{
public List<Order> Orders { get; set; }
public Management()
{
Item i1 = new Item("Item1", 2.0M, 5);
Item i2 = new Item("Item2", 3.0M, 6);
Item i3 = new Item("Item1", 2.0M, 7);
Orders = new List<Order>()
{
new Order(1, new Item[]{i1, i2}),
new Order(2, new Item[]{i3}),
new Order(3, new Item[]{i1, i3}),
};
}
//displays the total number of ordered items for all Orders with the given name on the console.
public void PrintQuantityForSingleItem(string itemName)
{
var result = (from x in Orders
select x.Items).ToList();
int counter = 0;
for (int i = 0; i < result.Count(); i++)
{
for (int a = 0; a < result[i].Count(); a++)
{
if (result[i][a].Name == itemName)
{
counter = counter + result[i][a].Quantity;
}
Console.WriteLine(result[i][a].Name);
}
}
Console.WriteLine(itemName + " " + counter);//for example: shows 24 for item1
}
}
You'll need to select all order items, group them by name and then calculate the sum value for the Quantity. The final step is to get the calculated sum value by item name and display it
public void PrintQuantityForSingleItem(string itemName)
{
var results = Orders
.SelectMany(o => o.Items)
.GroupBy(i => i.Name)
.Select(g => new { Item = g.Key, Sum = g.Sum(i => i.Quantity) });
var item = results.FirstOrDefault(r => r.Item.Equals(itemName, StringComparison.OrdinalIgnoreCase));
Console.WriteLine(itemName + " " + item?.Sum);//shows 24 for item1
}
Welcome to SO. It is obviously not advisable to look up items by name, but ignoring aspects of the design, here is one way of doing it:
var result = Orders.SelectMany(i => i.Items)
.Where(i => i.Name == itemName)
.Sum(i => i.Quantity);
Console.WriteLine($"{itemName}: {result}"); //24
Output:
Item1: 24
You can try the following,
public void PrintQuantityForSingleItem(string itemName)
{
var res = Orders.Select(x=>x.Items).Sum(y => y.Where(z => z.Name == itemName).Sum(t => t.Quantity));
Console.WriteLine(res);
Console.ReadKey();
}
It prints 24
You can use Linq :
decimal counter = Orders
.SelectMany(o => o.Items)
.Where(i => i.Name == itemName)
.Sum(i => i.Quantity);
I hope you find this helpful.
Related
I have this list
List<Order> OL = new List<Order>()
{
new Order("O-1","P1",200,2),
new Order("O-2","P1",200,3),
new Order("O-3","P1",1000,1),
new Order("O-4","P2",200,2)
};
The Order class :
class Order
{
public string ID { get; set; }
public string Product { get; set; }
public int Price { get; set; }
public int Quantity { get; set; }
public int Total { get { return Price * Quantity; } }
public Order(string _ID, string _Product, int _Price, int _Quantity)
{
ID = _ID;
Product = _Product;
Price = _Price;
Quantity = _Quantity;
}
public Order()
{
}
}
So I want to return the name and the counting (Number of times the product repeated in orders) for each product.
I tried :
var P = OL.OrderByDescending(x => x.Product.Count()).Take(2);
MessageBox.Show(P.ElementAt(0).Product);
But just getting the product name, Please any help? and thanks in advance.
How about:
var groupedProducts = OL.GroupBy(o => o.Product)
.Select(g => new { Product = g.Key, Quantity = g.Count() })
.OrderByDescending(p => p.Quantity);
Group by Product then sort by Count()
var P = OL.GroupBy(x => x.Product)
.OrderByDescending(x => x.Count())
.Select(g => new { Product = g.Key, Count = g.Count() });
The Text File Data is Like Below:
S.No Name Description Quantity Rate Discount Amount
1 Apple Friut is 12 24.02 0 242
Good for
health
2 Orange Friut 5 12.22 3 128
3 Banana Friut 5 12.22 3 128
4 Grapes Friut 5 12.22 3 128
I want to add all the Rows& Columns in list but Description column have multiple Rows in single item. How can I Solve this. I add My Existing Code Here:
My Existing Code is as follows:
class Program
{
static void Main(string[] args)
{
var dd = File.ReadAllLines(
"C:\\Users\\Trainee\\Desktop\\Saravanan_Test\\27.8.2018\\Inputfile.txt")
.Skip(1)
.Where(s => s.Length > 1)
.Select(x => splits(x)).ToList();
foreach (var item in dd)
{
Console.WriteLine(item.id+"\t"
+ item.Name+"\t"
+ item.Description+"\t"
+ item.Quantity+"\t"
+ item.Rate+"\t"
+ item.Discount+"\t"
+ item.Amount);
}
Console.ReadKey();
}
private static Class1 splits(string x)
{
var columns = x.Split('\t').Where(c => c != "").ToList();
return new Class1
{
id = Convert.ToInt32(columns[0]),
Name = columns[1],
Description = columns[2],
Quantity = Convert.ToInt32(columns[3]),
Rate = Convert.ToDouble(columns[4]),
Discount = Convert.ToInt32(columns[5]),
Amount = int.Parse(columns[6])
};
}
}
class Class1
{
public int id { get; set; }
public string Name { get; set; }
public String Description { get; set; }
public int Quantity { get; set; }
public double Rate { get; set; }
public int Discount { get; set; }
public int Amount { get; set; }
}
I want to store data into list like:
list.Add(new{ sno=1, Name="Apple",
Description="Friut is good for Health",
Quantity=12, Rate=24.02, Discount=0,
Amount=242 });
Thanks in Advance.
NOTE: This solution is based on the file shared in question. Data is separated by spaces and format is not advisable to use. Answering to help person with content format he has. Tested and working.
static void Main(string[] args)
{
List<Data> list = new List<Data>();
var dd = File.ReadAllLines(#"C:\Users\XXXX\Desktop\test.txt")
.Skip(1)
.Where(s => s.Length > 1).ToList();
foreach (var item in dd)
{
var columns = item.Split('\t').Where(c => c.Trim() != string.Empty).ToList();
if (columns != null && columns.Count > 0)
{
int id;
if (int.TryParse(columns[0], out id))
{
list.Add(new Data()
{
id = Convert.ToInt32(columns[0]),
Name = columns[1],
Description = columns[2],
Quantity = Convert.ToInt32(columns[3]),
Rate = Convert.ToDouble(columns[4]),
Discount = Convert.ToInt32(columns[5]),
Amount = int.Parse(columns[6])
});
}
else
{
list.Last().Description += columns[0];
}
}
}
Console.ReadLine();
}
I have a list of a class Status.
public partial class Status
{
public string thisStatus { get; set; }
public int a { get; set; }
public int b { get; set; }
//more fields
}
Then I want to group by my list by each 3 rows.
for example, I have 7 status : status1 ~ status7. Then it will grouped by becomes [status1-status3], [status4-status6], [status7]
List<Status> tmpResult = new List<Status>();
//tmpResult get data
var grouped = tmpResult
.Select((x, index) => new { x, index })
.GroupBy(g => g.index / 3, i => i.x);
foreach (var stat in grouped)
{
int totalDistance = stat.Select(x => x.a).Sum();
int avgSpeed = Convert.ToInt32(stat.Select(x => x.b).Average());
Status firstInGroup = stat.First(); //here I got an error
}
Cannot implicitly convert type "< anonymous type: X.Models.Status x, int index>" to "X.Models.Status"
Any help would be appreciated. thx
I have a Model called JobReport which looks like this (simplified)
public class JobReport
{
public JobReport()
{
WorkOrders = new List<WorkOrder>();
}
public int JobID { get; set; }
public decimal WorkOrderTotal {get; set; }
public List<WorkOrder> WorkOrders{ get; set; }
}
public class WorkOrder
{
public WorkOrder()
{
Total = 0;
}
public string Trade { get; set; }
public int WorkOrderID { get; set; }
public decimal? Total { get; set; }
}
I now have a Linq query which gets me all the Jobs that have WorkOrders that have a trade which is in a passed array thanks to Linq Query where related entity contains value from array:
jobs = jobs
.Where(x => x.WorkOrders.Any(y => trades.Contains(y.Trade)));
How do I now get the WorkOrderTotal, which is the sum of the Total in the workorders that meet the predicate of the above query? I can't see how to add .Sum() anywhere?
EDIT
Just to confirm, each job needs the sum of it's workorders that are in the given trades.
Perhaps a slightly easier solution to those already posted would be to add a property to your JobReport called WorkOrderValue:
public decimal? WorkOrdersValue { get; set; }
Now you can query on the jobs that meet your criteria:
jobs = jobs
.Where(x => x.WorkOrders
.Any(y => trades.Contains(y.Trade.ToLower())))
.ToList();
And separately calculate the total for each job:
foreach (var job in jobs)
{
job.WorkOrdersValue = job.WorkOrders.Where
(y => trades.Contains(y.Trade.ToLower())).Sum(wo => wo.Total);
}
Try something like this:
IEnumerable<decimal> workOrderTotals = jobs
.Where(x => x.WorkOrders.Any(y => trades.Contains(y.Trade)))
.Select( j => j.WorkOrders.Sum(wo => wo.Total ?? 0));
And here's a test case :
var jobs = new List<JobReport>();
jobs.Add(new JobReport{ WorkOrders = new List<WorkOrder>{ new WorkOrder{ Total = 10} }});
jobs.Add(new JobReport { WorkOrders = new List<WorkOrder> { new WorkOrder { Total = 10 }, new WorkOrder { Total = 10 } } });
The result is an enumerable containing 2 values 10 , 20
Considering this as the test data
JobReport job1 = new JobReport();
job1.JobID = 1;
job1.WorkOrders.Add(new WorkOrder() { WorkOrderID = 2, Trade = "trade1", Total = 10});
job1.WorkOrders.Add(new WorkOrder() { WorkOrderID = 3, Trade = "trade2", Total = 20 });
job1.WorkOrders.Add(new WorkOrder() { WorkOrderID = 4, Trade = "trade1", Total = 25 });
JobReport job2 = new JobReport();
job2.JobID = 2;
job2.WorkOrders.Add(new WorkOrder() { WorkOrderID = 1, Trade = "trade1", Total = 10 });
job2.WorkOrders.Add(new WorkOrder() { WorkOrderID = 5, Trade = "trade2", Total = 20 });
job2.WorkOrders.Add(new WorkOrder() { WorkOrderID = 6, Trade = "trade2", Total = 30 });
job2.WorkOrders.Add(new WorkOrder() { WorkOrderID = 7, Trade = "trade3", Total = 10 });
List<JobReport> jobs = new List<JobReport>();
jobs.Add(job1);
jobs.Add(job2);
You could do something like this.
var groupedJobs = jobs.GroupBy(a => a.JobID)
.Select(b => new { JobId = b.Key, WorkOrdersByTrade = b.Select(c => c.WorkOrders.GroupBy(d => d.Trade)
.Select(g => new { Trade = g.Key, tradeSum = g.Sum(s => s.Total) })) });
Further by defining the following classes
public class TradeTotal
{
public string Trade { get; set; }
public decimal? Total { get; set; }
}
public class JobTrade
{
public int JobId { get; set; }
public List<TradeTotal> TradeTotals { get; set; }
}
You can get the results in the format that you wanted
var JobTradeList = groupedJobs.Select(x => new JobTrade() { JobId = x.JobId, TradeTotals = x.WorkOrdersByTrade.SelectMany(s => s.Select(v => new TradeTotal() { Total = v.tradeSum, Trade = v.Trade })).ToList() }).ToList();
Code may be not 100% clean; but I think this is what you are after.
The next code is functional, but I want know if exist a better way to do this function.
With linq I get a list with 4 elements, but I needed add those elements in a list of ProposalItems, the next code is the type of the list
private class ProposalItems
{
public double Quantity { get; set; }
public double Price { get; set; }
public int Row { get; set; }
public double Total { get; set; }
}
And the next code is the method:
internal List<ProposalItems> GetProposalItems(int tradeId, int contendantId)
{
using (var db = new Entities())
{
//declare the list
List<ProposalItems> items = new List<ProposalItems>();
//query in linq
var data = db.ES_SC_PropuestasPrecios
.Join(db.ES_SC_CatalogoConceptos,
prices => prices.renglon,
concept => concept.renglon,
(prices, concept) => new { ES_SC_PropuestasPrecios = prices, ES_SC_CatalogoConceptos = concept })
.Where(w => w.ES_SC_CatalogoConceptos.idconcurso == tradeId && w.ES_SC_PropuestasPrecios.idconcursante == contendantId)
//select the items
.Select(s => new
{
Row = s.ES_SC_CatalogoConceptos.renglon,
Quantity = s.ES_SC_CatalogoConceptos.cantidad,
Price = s.ES_SC_PropuestasPrecios.preciounitario,
Total = s.ES_SC_PropuestasPrecios.importe
}).ToList();
// loop to add the item in the list
foreach (var item in data)
{
items.Add(new ProposalItems { Row = (int)item.Row, Price = (double)item.Price, Quantity = (double)item.Quantity, Total = (double)item.Total });
}
return items;
}
}
Try to substitute your current select for this
.Select(s => new ProposalItems {
Row = (int)s.ES_SC_CatalogoConceptos.renglon,,
Price = (double)s.ES_SC_PropuestasPrecios.preciounitario,
Quantity = (double)s.ES_SC_CatalogoConceptos.cantidad,
Total = (double)s.ES_SC_PropuestasPrecios.importe
}).ToList();