I have following Table with records for ActivityLog:
ID, UserId, Category, Created
1 11 DeAssigned 05/10/2012
2 11 LogIn 05/11/2012
3 20 Assigned 06/15/2012
4 11 Assigned 06/10/2012
5 20 DeAssigned 06/13/2012
6 20 Assigned 07/12/2012
7 11 DeAssigned 07/16/2012
8 20 Assigned 08/15/2012
...
now i want to query the Table to create same struct the same Result such as this:
var data = new[] {
new { Month = "05", Assigned = 14, DeAssigned = 5, LogIn=1 },
new { Month = "06", Assigned = 5, DeAssigned = 2, LogIn=0 },
new { Month = "07", Assigned = 50, DeAssigned = 8, LogIn=0 },
new { Month = "08", Assigned = 15, DeAssigned = 1, LogIn=0 }
};
what i have achieved:
var result = (from l in repoA.GetAll()
where l.Created >= System.DateTime.Now.AddYears(-1)
group l by new { l.Created.Value.Month, l.Category }
into groups
orderby groups.Key.Month
select new
{
Month = groups.Key.Month,
Category = groups.Key.Category,
Count = groups.Count()
});
there is not optimal result but count all Activity's grouped by Month:
[0] {Month = 6, Category = Assigned, Count = 2}
[0] {Month = 6, Category = Designed, Count = 1}
[0] {Month = 6, Category = LogIn, Count = 1}
[0] {Month = 7, Category = Assigned, Count = 3}
How can i query my Table to Format my Result in "Horizontal Counted" format?
Or simplier:
var result = (from l in repoA.GetAll()
where l.Created >= System.DateTime.Now.AddYears(-1)
group l by l.Created.Month into groups
orderby groups.Key ascending
select new
{
Month = groups.Key,
Assigned = groups.Where(g => g.Category == "Assigned").Count(),
Deassigned = groups.Where(g => g.Category == "DeAssigned").Count(),
LogIn = groups.Where(g => g.Category == "LogIn").Count()
});
Related
I am facing an issue with counting the number of occurrences by date in C#. Should I use Linq to filter it? Please advise. Thank you.
Date
Player ID
1/1/2001
23
1/1/2001
29
1/1/2001
24
3/1/2001
22
3/1/2001
23
My preferred output should be
Date
No. Of Players
1/1/2001
3
2/1/2001
0
3/1/2001
2
This is my current code, how can I do it within the select:
var convertTable = dataPageTable.AsEnumerable();
Records = new List<List<ContentOutputModel>>(convertTable.Select(dr =>
{
var playerId = dr.GetColumn<long>("PlayerID").ToString();
var dateInt = dr.GetColumn<int>("Date").ToString();
var dateStr = dateInt.Substring(6, 2) + "/" + dateInt.Substring(4, 2) + "/" + dateInt.Substring(0, 4);
var output = new List<ContentOutputModel>(new ContentOutputModel[] {
new ContentOutputModel() { Text = dateStr },
new ContentOutputModel() { Text = playerId },
});
return output;
}));
Here's the cleanest that I could come up with:
List<Player> players = new List<Player>()
{
new Player() { Date = new DateTime(2021, 1, 1), ID = 23 },
new Player() { Date = new DateTime(2021, 1, 1), ID = 29 },
new Player() { Date = new DateTime(2021, 1, 1), ID = 24 },
new Player() { Date = new DateTime(2021, 1, 3), ID = 22 },
new Player() { Date = new DateTime(2021, 1, 3), ID = 23 }
};
var first = players.Min(p => p.Date);
var last = players.Max(p => p.Date);
var days = last.Subtract(first).Days + 1;
var lookup = players.ToLookup(p => p.Date);
var output =
from n in Enumerable.Range(0, days)
let Date = first.AddDays(n)
select new
{
Date,
Count = lookup[Date].Count(),
};
That gives me:
You can achieve by Group() via System.Linq.
Order players by Date and get startDate and endDate.
Generate an array with dates from startDate to endDate.
3.1 With group to count player(s) by Date.
3.2 Left join result from (2) with the result (3.1) to get Date and Count.
using System.Linq;
using System.Collections.Generic;
List<Player> players = new List<Player>
{
new Player{Date = new DateTime(2021, 1, 1), ID = 23},
new Player{Date = new DateTime(2021, 1, 1), ID = 29},
new Player{Date = new DateTime(2021, 1, 1), ID = 24},
new Player{Date = new DateTime(2021, 1, 3), ID = 22},
new Player{Date = new DateTime(2021, 1, 3), ID = 23}
};
var startDate = players.OrderBy(x => x.Date)
.First()
.Date;
var endDate = players.OrderBy(x => x.Date)
.Last()
.Date;
var dates = Enumerable.Range(0, 1 + endDate.Subtract(startDate).Days)
.Select(offset => startDate.AddDays(offset))
.ToArray();
var result = (from a in dates
join b in
(
from p in players
group p by p.Date into g
select new { Date = g.Key, Count = g.Count() }
) on a.Date equals b.Date into ab
from b in ab.DefaultIfEmpty()
select new { Date = a.Date, Count = b != null ? b.Count : 0 }
);
Sample program
Output
Date: 1/1/2021, Count: 3
Date: 2/1/2021, Count: 0
Date: 3/1/2021, Count: 2
You can use linq to do this as long as it can enumerate through a list or some other IEnumerable. Try this:
var playersSorted = yourlist.GroupBy(x => x.Date)
.Where(g => g.Any())
.Select(y => new {Date = y.Key, Count = y.Count()}).ToList();
var playersgroup = from e in players
group e by Date into g
select new { Date= g.Key, NoOfPlayers = g.Count() };
need some help with my foreach to recongonize the empty record and fill the gap with "-";
let's say we have 30min, 45min, 90min, 120min and not 60min in the case:
It can count the total records of each id, let's say the maximum is 5, 30min, 45min, 60min, 90min and 120min.
if there are 3, then it could check which is missing and than can fill with "-".
Same ideia of the script.
List<Treatment> treatment = new List<Treatment>();
treatment.Add(new Treatment { id = 1, treatmentNameId = 11, duration = "30", price = 30 });
treatment.Add(new Treatment { id = 1, treatmentNameId = 11, duration = "45", price = 45 });
treatment.Add(new Treatment { id = 1, treatmentNameId = 11, duration = "60", price = 60 });
treatment.Add(new Treatment { id = 1, treatmentNameId = 2, duration = "30", price = 30 });
//treatment.Add(new Treatment { id = 1, treatmentNameId = 2, duration = "45", price = 45 });
treatment.Add(new Treatment { id = 1, treatmentNameId = 2, duration = "60", price = 60 });
var newList = (from t in treatment
select t)
.AsQueryable().ToList();
List<List> newList= new List<List>();
foreach (var item in newList)
{
if (item.duration == "30")
{
newList.Add(new List { treatmentNameId = item.treatmentNameId, thirtyMin = "30" });
}
if (item.duration == "45")
{
newList.Add(new List { treatmentNameId = item.treatmentNameId, fortyFive= "45" });
}
if (item.duration == "60")
{
newList.Add(new List { treatmentNameId = item.treatmentNameId, sixty= "60" });
}
}
The end result should like something as,
id:1 30, 45, 60, -
id:2 30, - , 60, 90
id:3 - , 45, -, 90
etc...
Many many thanks for the help.
I'm not going to provide a very detailed explanation of all this, but conceptually I'm just grouping by treatmentNameId and then doing something very similar to an outer join in SQL. If the group join comes up empty for the duration, I'm selecting '-' instead of the duration. Using anonymous types for brevity.
var durations = new[] {"15", "30", "45", "60"};
var results = treatments
.GroupBy(t => t.treatmentNameId).Select(group => new
{
treatmentNameId = group.Key,
durations = durations.GroupJoin(group, s => s, g => g.duration,
(s, grouping) => !grouping.Any() ? "-" : s)
});
foreach (var result in results)
{
Console.WriteLine(result.treatmentNameId + ": " + string.Join(", ", result.durations));
}
This results in:
11: -, 30, 45, 60
2: -, 30, -, 60
If you have problems with something more specific, I'd be happy to explain further.
This question already has answers here:
C# List grouping and assigning a value
(2 answers)
Closed 6 years ago.
I need help to solve this.
I have used Console Application to solve this and I am stuck.
Every row in ORDER needs to have an unique value inside a group med same GROUP-value. The Max-value on ORDER inside the group need to be Count of Rows -1 and Min value has to be 0. The sorting doesnt matter.
It only needs to be an UNIQUE value between min and max.
Example: 012345 or 041532
ID GROUP VALUE ORDER
1 1 10 0
2 1 2 0
3 2 1 0
4 3 2 0
5 3 6 0
6 3 1 0
7 3 9 0
GROUP 1 have 2(-1) Rows, ORDER value has to be 0-1.
GROUP 2 have 1(-1) Rows, ORDER value has to be 0.
GROUP 3 have 4(-1) Rows, ORDER value has to be 0-3.
End Result:
ID GROUP VALUE ORDER
1 1 10 0
2 1 2 1
3 2 1 0
4 3 2 0
5 3 6 1
6 3 1 3
7 3 9 2
Here is the properties i have used.
public class OrderRow
{
public int ID { get; set; }
public int GROUP { get; set; }
public int VALUE { get; set; }
public int ORDER { get; set; }
}
new OrderRow {ID = 1, GROUP = 1, VALUE = 10, ORDER = 0},
new OrderRow {ID = 2, GROUP = 1, VALUE = 2, ORDER = 0},
new OrderRow {ID = 3, GROUP = 2, VALUE = 1, ORDER = 0},
new OrderRow {ID = 4, GROUP = 3, VALUE = 2, ORDER = 0},
new OrderRow {ID = 5, GROUP = 3, VALUE = 6, ORDER = 0},
new OrderRow {ID = 6, GROUP = 3, VALUE = 1, ORDER = 0},
new OrderRow {ID = 7, GROUP = 3, VALUE = 9, ORDER = 0},
THANKS
I'd go like follows:
List<OrderRow> orders = new List<OrderRow>() {
new OrderRow { ID = 1, GROUP = 1, VALUE = 10, ORDER = 0 },
new OrderRow { ID = 2, GROUP = 1, VALUE = 2, ORDER = 0 },
new OrderRow { ID = 3, GROUP = 2, VALUE = 1, ORDER = 0 },
new OrderRow { ID = 4, GROUP = 3, VALUE = 2, ORDER = 0 },
new OrderRow { ID = 5, GROUP = 3, VALUE = 6, ORDER = 0 },
new OrderRow { ID = 6, GROUP = 3, VALUE = 1, ORDER = 0 },
new OrderRow { ID = 7, GROUP = 3, VALUE = 9, ORDER = 0 },
};
foreach (var item in orders.GroupBy(order => order.GROUP))
{
int order = 0;
foreach (var item2 in item)
{
item2.ORDER = order++;
}
}
I have problems getting the correct result of this linq.
var transactions = from trans in tblMemberInfo.AsEnumerable()
orderby trans.Field<Int32>("AGE") ascending
group trans by trans.Field<Int32>("AGE") into groupTrans
select new
{
ZeroToSix = groupTrans.Count(age => age.Field<Int32>("AGE") >= 0 && age.Field<Int32>("AGE") <= 6)
};
I have a data table which contains data below. now, I want to sum all the age count where
age is between 0 to 5.
AGE Count
0 6
1 6
2 7
3 5
4 5
5 20
6 5
7 5
8 5
9 5
10 5
I would like to see the result like this.
Age
ZeroToFive = 49
AboveSix = 25
Check this:
// mock data
var data = new List<dynamic> {
new { Age = 0, Count = 6 },
new { Age = 1, Count = 6 },
new { Age = 2, Count = 7 },
new { Age = 3, Count = 5 },
new { Age = 4, Count = 5 },
new { Age = 5, Count = 20 },
new { Age = 6, Count = 5 },
new { Age = 7, Count = 5 },
new { Age = 8, Count = 5 },
new { Age = 9, Count = 5 },
new { Age = 10, Count = 5 },
};
var age = new {
ZeroToFive = data.Where(x => x.Age < 6).Sum(x => x.Count),
AboveSix = data.Where(x => x.Age >= 6).Sum(x => x.Count)
};
var data = new[] {
new { Id = 0, Cat = 1, Price = 2 },
new { Id = 1, Cat = 1, Price = 10 },
new { Id = 2, Cat = 1, Price = 30 },
new { Id = 3, Cat = 2, Price = 50 },
new { Id = 4, Cat = 2, Price = 120 },
new { Id = 5, Cat = 2, Price = 200 },
new { Id = 6, Cat = 2, Price = 1024 },
};
var ranges = new[] { 10, 50, 100, 500 };
Needed output is grouped price count by equal or greater than the range used according categories.
(in one linq statement)
cat range count
-------------------------------------
1 10 2 (In 1. categories there is 2 item that price >= 10(range) [10;30])
2 10 4 (In 2. categories there is 4 item that price >= 10(range) [50;120;200;1024])
2 50 4 ....
2 100 3 ....
2 500 1 (In 2. categories there is 1 item that price >= 500(range) [1024])
Try this:
var data = new[] {
new { Id = 0, Cat = 1, Price = 2 },
new { Id = 1, Cat = 1, Price = 10 },
new { Id = 2, Cat = 1, Price = 30 },
new { Id = 3, Cat = 2, Price = 50 },
new { Id = 4, Cat = 2, Price = 120 },
new { Id = 5, Cat = 2, Price = 200 },
new { Id = 6, Cat = 2, Price = 1024 },
};
var ranges = new[] { 10, 50, 100, 500 };
var result = from r in ranges
from g in data
where g.Price >= r
select new {g.Cat, Price=r};
var groupedData =
from d in result
group d by new{d.Cat, d.Price} into g
select new{Cat=g.Key.Cat, Price=g.Key.Price, TotalCount=g.Count()};
This should work:
var values =
data.SelectMany(x => ranges.Where(y => x.Price >= y)
.Select(y => new { Record = x, Range = y }))
.GroupBy(x => new { Cat = x.Record.Cat, Range = x.Range })
.Select(x => new { Cat = x.Key.Cat, Range = x.Key.Range, Count = x.Count()});
Results:
{ Cat = 1, Range = 10, Count = 2 }
{ Cat = 2, Range = 10, Count = 4 }
{ Cat = 2, Range = 50, Count = 4 }
{ Cat = 2, Range = 100, Count = 3 }
{ Cat = 2, Range = 500, Count = 1 }