I have an situation where I have defined a class like following:
class Item
{
List<DateTime> _TransactonDatesPast30Days = new List<DateTime>();
}
So the situation can be like following:
I have 25 transaction dates in the list...
Next item:
40 transaction dates
So now I have a List of items with all these parameters like following:
List<Item> _items = new List<Item>();
Now I need to group by the list within a list to get number of sales per day in final list...
For example:
12th of December occured 14 times in all List and now it's count is 14 , which will represent the number of sales made for that date...
In normal circumstances I would group them by like this:
ViewBag.LineGraph = lista
.GroupBy(l => l.TrasnactionDate)
.Select(cl => new Item
{
TrasnactionDate = cl.Key.TrasnactionDate.Date,
SaleNumber = cl.Count(c => cl.Key)
})
.OrderBy(x => x.TrasnactionDate)
.Where(x=>x.SaleNumber>0)
.ToList();
But it confuses me when I have list within a list that I need to group by, I have no ideas what to do now here when I have a list within a list that needs to grouped by the date...
// This wasn't grouping I guess
var result = _items.Select(x => x._TransactonDatesPast30Days).GroupBy(y => y).Select(x => new Item {_TransactonDatesPast30Days = x.Key ,Salesnumber = x.Count()});
Take this Solution: Update 2
var resultt2 = _items.Select(x => x._TransactonDatesPast30Days).
Select(r => r.GroupBy(x => x).Select(l => new Item { _TransactonDatesPast30Days = new List<DateTime>{l.Key}, Salesnumber = l.Count() }));
Related
I have a list with date and Fileno as values. I need to find the duplicate date and based on that find the highest Fileno.Then add that keyvalue pair and the distinct pair to the final list. The result should be as shown below.I am able to get the duplicate date but how to compare the duplicate dates and find the highest fileno?
Key Date Fileno
1 10/8/1980 1234
2 10/8/1980 1345
3 8/6/1970 4567
Result
2 10/8/1980 1345
3 8/6/1970 4567
Code
var list = new List<valuepair>();
list.Add(new valuepair {no=key,comdate=date,filnum=fileno})
Var dup= list.GroupBy(x => comdate.Value).Where(x => comdate.Count() > 1)
You're almost there, except the code you've posted is not compilable (!). You just need to take the element with the highest "filnum" from each group:
var list = new List<valuepair>();
list.Add(new valuepair { no=1, comdate="10/8/1980", filnum=1234 });
list.Add(new valuepair { no=2, comdate="10/8/1980", filnum=1345 });
list.Add(new valuepair { no=3, comdate="8/6/1970", filnum=4567 });
var listWithoutDuplicates = list.GroupBy(x => x.comdate)
// For each group (in which items have identical dates) take only
// the one with the highest "filnum"
.Select(group => group.OrderBy(x => x.filnum).First())
.ToList();
Try this:
var result = data
.GroupBy(
i => i.Date,
(key, group) => group.Single(x => x.Fileno == group.Max(y => y.Fileno)))
.ToList();
The below code groups the result (a List of ClassTypeObject with 500,000 items) into List<a> type.
The GroupBy takes around 40 to 50 sec when executed. Is there any way to optimize this?
var groupByTest = result.
GroupBy(g => new
{
First = g.Field1
}).
Select(gp => new
{
gp.Key.Field1,
InnerList = result.Where(x => x.Field1 == gp.Key.Field1).ToList()
}).ToList();
You are selecting InnerList from non-grouped collection i.e. result that's why your query is taking time. You can change the inner query assignment as
InnerList = gp.ToList()
as gp is already grouped based on Field1.
Full Code
var groupByTest = result.
GroupBy(g => new
{
First = g.Field1
}).
Select(gp => new
{
gp.Key.Field1,
InnerList = gp.ToList()
}).ToList();
The way this query is written InnerList ends up containing just the items in the group. In its current form, the original source is scanned once for each group key. The equivalent:
var groupByTest = result.GroupBy(g => g.Field1)
.Select(gp => new {
Field1=gp.Key,
InnerList = gp.ToList()})
.ToList();
Would scan the source only once.
Once this is fixed, the query can be parallelized easily with AsParallel()
var groupByTest = result.AsParallel()
.GroupBy(g => g.Field1)
.Select(gp => new {
Field1=gp.Key,
InnerList = gp.ToList()})
.ToList();
This will use all cores in the machine to partition the data, group them and construct the final list
I am displaying a list of events by day from SQL database using the code:
IEnumerable<EventInstance> distinctDate = instances
.GroupBy(e => e.StartDate.Date)
.Select(group => group.First());
foreach (var instance in distinctDate)
{
// code to display here
}
What I am trying to do is divide them up by month on the page, so in between each month going down the page, i can put the Month Heading in a H3 tag
If you want one event for each day then grouped by month I think this is what you are looking for. Note you have to also group by year to avoid lumping dates from different years together. I also added a order by in there to make sure the events are in order by date.
var distinctDate = instances
.GroupBy(e => e.StartDate.Date)
.Select(grp => grp.First())
.OrderyBy(e => e.StartDate.Date)
.GroupBy(e => new { e.StartDate.Year, e.StartDate.Month });
Then you would do something like this
foreach(var monthGrouping in distinctDate)
{
var month = monthGrouping.Key.Month;
foreach(var singleDayEvent in monthGrouping)
{
var date = singleDayEvent.StartDate;
}
}
I have a list of string that i want to order by quantity. The List contain a list of Order-CreationDate with datetime values. I'm converting this values to strings as as i will need that for later.
My current output is a list of CreationDate that looks like this.
2014-04-05
2014-04-05
2014-04-05
2014-04-05
2014-04-06
2014-04-06
2014-04-06
...
I get a list of dates as expected but i want to group number of dates by the date. This mean i need another variable with number of total orders. Ive tried creating a new variable, using a for loop and linq queries but not getting the results I want.
How can I get number of orders by CreationDate? I need to count total number of orders by CreationDate but I can't find a way to do this.
The expected output would be:
2014-04-05 4 - representing 4 orders that date
2014-04-06 3 - representing 3 orders that date.
This what my code looks like:
List<string> TotalOrdersPaid = new List<string>();
foreach (var order in orders)
{
if (order.PaymentStatus == PaymentStatus.Paid)
{
string Created = order.CreatedOnUtc.Date.ToString("yyyy-MM-dd");
order.CreatedOnUtc = DateTime.ParseExact(Created, "yyyy-MM-dd", CultureInfo.InvariantCulture);
TotalOrdersPaid.Add(Created);
}
}
Eg TotalOrdersPaid should contain a list with number of orders by CreationDate.
What is a good way to achieve this?
Thanks
basically, you just need a group by and and ordering.
var result = orders//add any where clause needed
.GroupBy(m => m)
.Select(m => new {
cnt = m.Count(),
date = m.Key
})
.OrderByDescending(m => m.cnt);
Of course, you can add any DateTime.Parse / ParseExact in the Select, and / or project to a corresponding class.
To group the orders by date, take following LinQ lambda expression:
var grouped = orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc);
Now, all paid orders are grouped by date. To count the orders per date, select the key which is the date, and the Count() will count all orders for that date.
var counted = grouped.Select(s => new { Date = s.Key, Count = s.Count() });
Edit:
In one statement:
var result = orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc)
.Select(s => new { Date = s.Key, Count = s.Count() });
Based on your list of dates, the output will look like:
Date Count
5/04/2014 4
6/04/2014 3
Update:
If you want to put more properties in the anonymous type that will be returned from the Select() method, sumply just add them. If, for example, you want the date, the count and the list of orders for that date, use following line of code:
var result = orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc)
.Select(s => new
{
Date = s.Key,
Count = s.Count(),
Items = s.ToList()
});
Now you can do following:
foreach(var orderGroup in result)
{
Console.WriteLine(String.Format("Number of orders for {0}: {1}", orderGroup.Date, orderGroup.Count));
foreach(var order in orderGroup.Items)
{
Console.WriteLine(order.Name);
}
}
This will loop over all grouped items and display a sentence like:
Number of orders for 5/04/2014: 4
And then it will display the name of each order for that date (if your order has a property Name). Hope this clears everything out.
I am trying to get the sum of the value from list of list using linq ?my data is as below code
List<List<string>> allData = new List<List<string>>();
using (StreamReader reader = new StreamReader(path))
{
while (!reader.EndOfStream)
{
List<string> dataList;
dataList = reader.ReadLine().Split('|').ToList();
allData.Add(dataList);
}
}
which gives me data in allData as below
allData-->[0]-->[0]-'name1'
[1]-'sub'
[2]-'12'
[1]-->[0]-'name2'
[1]-'sub'
[2]-'15'
[2]-->[0]-'name1'
[1]-'sub2'
[2]-'15'
//and so on ....
i have applied group by that gives me grouping by the name but i am not able to figure out how to get the sum of the marks for each name ?
var grouped = allData.GroupBy(x => x[0]);
after this i get all matching name grouped into one but now how to get sum of the marks for that group ? any help would be great ?
Output should be name1=27 and name2=15 and so on.
Not sure if you want to get the sum of every group or the total. If it's the total then this should do the trick
var sum = allData.Sum(x => Int32.Parse(x[2]));
If it's per key then try the following
var all = allData
.GroupBy(x => x[0])
.Select(x => x.Sum(y => Int32.Parse(y[2]));
var grouped = allData.GroupBy(x => x[0])
.Select(g => new
{
Name = g.Key,
Sum = g.Sum(x => int.Parse(x[2]))
});
It will return an anonymous type instance for each group, with two properties: Name with your grouping key and Sum with sum of marks.
Sticking as much as possible to the LINQ query language:
var grouped = from d in allData
group d by i[0] into g
select new
{
Name = g.Key,
Sum = g.Sum(i => int.Parse(i[2]))
};
This will give you parallel List with each name and the count of how many times each name occurs.
var names = grouped.Select(s => s.Key).ToList();
var nameCount = grouped.Select(s => s.Count()).ToList();
Also... you may want to add this when assigning alldata to grouped. I use this to get a List from greatest to least amount of occurrences.
var grouped = allData.GroupBy(x => x[0]).OrderByDescending(i => i.Count());