Linq Age GroupBy Aggregate Count - c#

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)
};

Related

Count rows in C# list with same Group and set as int value on other property [duplicate]

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++;
}
}

How to remove elements of list of array/structs that have 2 common elements

Having a list of structs OR maybe an array List each with 3 elements, like
12 8 7
5 1 0
7 3 2
10 6 5
6 2 1
8 4 3
6 1 5
7 2 6
8 3 7
9 4 8
11 7 6
13 9 8
11 6 10
12 7 11
13 8 12
14 9 13
I want to get rid of items that have 2 common subitems in list, in the example I would like to remove
5 1 0
6 2 1
6 1 5
7 3 2
7 2 6
8 4 3
8 3 7 has 2 same items as row 7,3,2
9 4 8 has 2 same items as row 8,4,3
10 6 5
11 7 6
11 6 10 has 2 same items as row 11,7,6
12 7 11 has 2 same items as row 11,7,10
12 8 7
13 8 12
13 9 8
14 9 13 has 2 same items as row 13,9,8
So using structs approach I am thinking in sorting the list by element A, then looping and comparing elements, in a way that If current element has 2 values equal to other element in list I do not add it to a result List, however I got stuck and do not know if there is a better approach
struct S
{
public int A;
public int B;
public int C;
}
public void test()
{
List<S> DataItems = new List<S>();
DataItems.Add(new S { A = 1, B = 2, C=3} );
DataItems.Add(new S { A = 12, B = 8, C = 7 });
DataItems.Add(new S { A = 5, B = 1, C = 0 });
DataItems.Add(new S { A = 7, B = 3, C = 2 });
DataItems.Add(new S { A = 10, B = 6, C = 5 });
DataItems.Add(new S { A = 6, B = 2, C = 1 });
DataItems.Add(new S { A = 8, B = 4, C = 3 });
DataItems.Add(new S { A = 6, B = 1, C = 5 });
DataItems.Add(new S { A = 7, B = 2, C = 6 });
DataItems.Add(new S { A = 8, B = 3, C = 7 });
DataItems.Add(new S { A = 9, B = 4, C = 8 });
DataItems.Add(new S { A = 11, B = 7, C = 6 });
DataItems.Add(new S { A = 13, B = 9, C = 8 });
DataItems.Add(new S { A = 11, B = 6, C = 10 });
DataItems.Add(new S { A = 12, B = 7, C = 11 });
DataItems.Add(new S { A = 13, B = 8, C = 12 });
DataItems.Add(new S { A = 14, B = 9, C = 13 });
var sortedList = DataItems.OrderBy(x => x.A);
List<S> resultList = new List<S>();
for (int i = 0; i < sortedList.Count (); i++)
{
for (int j = i+1; j < sortedList.Count(); j++)
{
if (sortedList.ElementAt(i).A == sortedList.ElementAt(j).A || sortedList.ElementAt(i).A == sortedList.ElementAt(j).B || sortedList.ElementAt(i).A == sortedList.ElementAt(j).C)
{
//ONE HIT, WAIT OTHER
}
}
}
}
Is there a more efficient way to get the list without having item with 2 same items so I would get, instead of hardcoding the solution?
5 1 0
6 2 1
6 1 5
7 3 2
7 2 6
8 4 3
10 6 5
11 7 6
12 8 7
13 8 12
13 9 8
Given an item...
{ A = 1, B = 2, C = 3 }
You have 3 possible combinations that could be repeated in another item, e.g.
AB, AC & BC which is {1, 2}, {1, 3} & {2, 3}
So what I would do is iterate through your list, add those combinations to a dictionary with a separator char (lowest number first so if B < A then add BA rather than AB). So you dictionary keys might be...
"1-2", "1-3", "2-3"
Now as you add each item, check if the key already exists, if it does then you can ignore that item (don't add it to the results list).
Performance-wise this would be once through the whole list and using the dictionary to check for items with 2 common numbers.
One way to solve it is by introducing intermediate methods in the struct S:
public struct S {
public int A;
public int B;
public int C;
public bool IsSimilarTo(S s) {
int similarity = HasElement(A, s) ? 1 : 0;
similarity += HasElement(B, s) ? 1 : 0;
return similarity >= 2 ? true : HasElement(C, s);
}
public bool HasElement(int val, S s) {
return val == s.A || val == s.B || val == s.C;
}
public int HasSimilarInList(List<S> list, int index) {
if (index == 0)
return -1;
for (int i = 0; i < index; ++i)//compare with the previous items
if (IsSimilarTo(list[i]))
return i;
return -1;
}
}
Then you can solve it like this without ordering:
public void test() {
List<S> DataItems = new List<S>();
DataItems.Add(new S { A = 1, B = 2, C = 3 });
DataItems.Add(new S { A = 12, B = 8, C = 7 });
DataItems.Add(new S { A = 5, B = 1, C = 0 });
DataItems.Add(new S { A = 7, B = 3, C = 2 });
DataItems.Add(new S { A = 10, B = 6, C = 5 });
DataItems.Add(new S { A = 6, B = 2, C = 1 });
DataItems.Add(new S { A = 8, B = 4, C = 3 });
DataItems.Add(new S { A = 6, B = 1, C = 5 });
DataItems.Add(new S { A = 7, B = 2, C = 6 });
DataItems.Add(new S { A = 8, B = 3, C = 7 });
DataItems.Add(new S { A = 9, B = 4, C = 8 });
DataItems.Add(new S { A = 11, B = 7, C = 6 });
DataItems.Add(new S { A = 13, B = 9, C = 8 });
DataItems.Add(new S { A = 11, B = 6, C = 10 });
DataItems.Add(new S { A = 12, B = 7, C = 11 });
DataItems.Add(new S { A = 13, B = 8, C = 12 });
DataItems.Add(new S { A = 14, B = 9, C = 13 });
int index = 1; //0-th element does not need to be checked
while (index < DataItems.Count) {
int isSimilarTo = DataItems[index].HasSimilarInList(DataItems, index);
if (isSimilarTo == -1) {
++index;
continue;
}
DataItems.RemoveAt(index);
}
}

Getting average of sums

Example collection:
List<Product> list = new List<Product>();
list.Add(new Product { Id = 1, Good = 50, Total = 50 });
list.Add(new Product { Id = 2, Good = 18, Total = 30 });
list.Add(new Product { Id = 2, Good = 15, Total = 30 });
list.Add(new Product { Id = 1, Good = 40, Total = 50 });
list.Add(new Product { Id = 3, Good = 6, Total = 10 });
list.Add(new Product { Id = 1, Good = 45, Total = 50 });
list.Add(new Product { Id = 3, Good = 8, Total = 10 });
Number of products is unknown. What I need as a result is to get a percentage for each distinct product good/total, and then an average for all products. In this case:
Product Id=1, GoodSum = 50 + 40 + 45 = 135, TotalSum = 50 + 50 + 50 = 150, Perc = 135/150
Product Id=2, GoodSum = 18 + 15 = 33, TotalSum = 30 + 30 = 60, Perc = 33/60
Product Id=3, GoodSum = 6 + 8 = 14, TotalSum = 10 + 10 = 20, Perc = 14/20
Avg = Avg(135/150 + 35/60 + 14/20) = Avg(0.9 + 0.55 + 0.7) = 2.15 / 3 = 7.17
Can we do this with Linq, I am only interested in Linq solution.
Try this :
var avg = list.GroupBy(G => G.Id)
.Select(G => (G.Sum(T => T.Good)/G.Sum(T => T.TotalSum)))
.Average();
Something like this?
var groups = list.GroupBy(l => l.Id)
.Select(g => new {
Id = g.Key,
GoodSum = g.Sum(i=>i.Good),
TotalSum= g.Sum(i=>i.Total),
Perc = (double) g.Sum(i=>i.Good) / g.Sum(i=>i.Total)
}
);
var average = groups.Average(g=>g.Perc);
Note that your answer for Avg should be 0.717 not 7.17.

Group by using linq (range + 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 }

Need help Linq Query Group By + Count

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()
});

Categories

Resources