Linq select all items where in list with groupby - c#

I have the following data as a list:
raceId data position
1 A 0
1 B 0
1 F 1
1 J 0
2 A 2
2 F 1
3 A 0
3 J 2
3 M 1
3 V 3
I need to get the total (count) of races where there are ALL matching letters with the same raceid.
I.E a search on 'A' and 'J' = 2 (race's 1 and 3)
In addition I need to get the position data for each.
raceId data position
1 A 0
1 J 0
3 A 0
3 J 2
So far I have the following code.
var dataValues = new string[] { 'A', 'J' };
var races = raceData
.GroupBy( ac => ac.raceId )
.Select( grp => grp.First() )
.Where( t =>
dataValues
.All( s =>
dataValues
.Contains( t.data )
)
);
var racecount = races.count()
The issue is that this returns all raceId values where there is either letter in the data.

This should work for you:
var results = raceData.GroupBy(rd => rd.raceId)
.Where(g => dataValues.All(dv => g.Select(g2 => g2.data).Contains(dv)));
int raceCount = results.Count();
var results2 = results
.SelectMany(g => g)
.Where(rd => dataValues.Contains(rd.data));
raceCount will give you 2 and results2 will give you the 4 records you're expecting.
It works for me with your provided data anyway!

var groupedRaces = from r in raceData
group r by r.raceId into gp
select new { raceId = gp.Key, Datas = gp.Select(g => g.data).ToArray() };
var raceIds = from r in groupedRaces
where dataVals.All(mv => r.Datas.Contains(mv))
select r.raceId;
var races = from r in raceData
where raceIds.Contains(r.raceId) && dataVals.Contains(r.data)
select r;

Try this,
list.GroupBy(t => t.raceID).SelectMany(k => k).Where(x => dataValues.Contains(x.data))
.Select(f=> new { f.data ,f.position,f.raceID}).ToList();
Result,
Hope helps,

Related

linq group by two columns and get only rows with same group by values

I want to retrieve data by group two columns ( Parent_Id and Name ) using LINQ and get the result only the rows with the same group by values.
Child
---------
Id Parent_Id Name
1 1 c1
2 1 c2
3 2 c1 <-----
4 2 c1 <-----
5 3 c2
6 3 c3
7 4 c4 <-----
As you can see, for Parent_Id 1 and 2, Name are different. So, I don't what those rows.
The result I want is like
Parent_Id Name
2 c1
4 c4
What I have tried is
from c in Child
group c by new
{
c.Parent_Id,
c.Name
} into gcs
select new Child_Model()
{
Parent_Id = gcs.Key.Parent_Id,
Name= gcs.Key.Name
};
But it return all rows.
As you describe it you should group by Parent_id only and get the groups that have distinct Names:
var result = children
.GroupBy(c => c.Parent_Id)
.Where(g => g.Select(t => t.Name).Distinct().Count() == 1)
.Select(g => new
{
Parent_Id = g.Key,
Name = g.Select(c => c.Name).First()
});
Reduced to final edit as per Gert Arnold's request:
var result = from r in (from c in children
where !children.Any(cc => cc.Id != c.Id &&
cc.Parent_Id == c.Parent_Id &&
cc.Name != c.Name)
select new {
Parent_Id = c.Parent_Id,
Name = c.Name
}).Distinct().ToList()
select new Child_Model
{
Parent_Id = r.Parent_Id,
Name = r.Name
};
var myModel = Child.GroupBy( c => $"{c.Parent_Id}|{c.Name}",
(k, list) => new Child_Model{
Parent_Id = list.First().Parent_Id,
Name = list.First().Parent_Id,
Count = list.Count()})
.Max (cm => cm.Count);
You can add a condition to filter result (groupName.Count() > 1):
from c in childs
group c by new { c.Parent_Id, c.Name } into gcs
where gcs.Count() > 1
select new { gcs.Key.Parent_Id, gcs.Key.Name }

LINQ Nested query with appropriate quantifiers and restrictions

I have two tables A & B as below:
Table A
W X Y
1 7 5
2 0 7
3 1 7
4 4 4
5 4 7
Table B
Q Z C D
1 1 7 5
2 1 0 7
3 1 1 7
4 1 4 4
I want to get those values of W for whom X & Y combination exactly matches those combination of C & D in Table B for whom Z = 1.
I have tried following query:
var query = A.Where(u =>
B.Where(a => a.Z == 1)
.Select(a => a.C)
.Contains(u.X))
.Where(u =>
B.Where(a => a.Z == 1)
.Select(a => a.D)
.Contains(u.Y))
.Select(a => new { WIds = a.W });
so in above cases, query result should give: W = {1,2,3,4} however I am getting extra value of 5 as well. W = {1,2,3,4,5}. I think it is not considering the combination as a whole. Can anyone help me what am I doing wrong in this query?
You can simply do it using Any:-
var result = A.Where(x =>
B.Any(p => p.Z == 1 && p.C == x.X && p.D == x.Y)
)
.Select(x => x.W);
Fiddle
The problem is that you are just checking whether the current X matches any C and the current Y matches any D, instead of matching them as a group. You could do this with a simpler query:
var query = A
.Where(a => B.Any(b => b.Z == 1 && b.C == a.X && b.D == a.Y))
.Select(a => new { WIds = a.W });
Can you try this ?
var query = A.Where(a =>
B.Any(b => b.Z == 1 && a.X == b.C && a.Y == b.D))
.Select(a => new { WIds = a.W });

How to split string by delimeter and multiple group by and count them in Linq?

I have a LogData List and which is designed like below.
public class LogDataEntity
{
public string IndexPattern;
public int Type;
public LogDataEntity(string pattern , int type)
{
IndexPattern = pattern;
Type = type;
}
}
List<LogDataEntity> list = new List<LogDataEntity>();
list.add(new LogDataEntity("1,2,9,10", 2));
list.add(new LogDataEntity("1,10", 1));
list.add(new LogDataEntity("1,2,3", 2));
list.add(new LogDataEntity("3,9,10", 3));
list.add(new LogDataEntity("9,10", 2));
list.add(new LogDataEntity("9,10", 2));
And i want the result like below.
[Index] [Type] [Count]
10 : 2 3
9 : 2 3
1 : 2 2
3 : 1 2
2 : 2 2
3 : 3 1
9 : 3 1
10 : 3 1
1 : 1 1
I want to group by and count not only splited string(indexpattern) but also
type too. And i want to count and show them by OrderByDescending(Count).
I think There is multiple group by.
How should i do this with Linq?
You can use SelectMany to create list of (Index, Type) pairs, then group by and count to do the rest:
var pairs = data.SelectMany(x => x.IndexPattern
.Split(",")
.Select(y => new {Index = y, Type = x.Type});
var res = from p in pairs
group p by new { p.Index, p.Type } into grp
select new {
Index = grp.Key.Index,
grp.Key.Type,
grp.Count()
};
(An order by clause can be added before the final Select as required.)
You've, probably, stuck in SelectMany; all the other commands are quite evident:
var result = list
.SelectMany(record => record
.IndexPattern
.Split(',')
.Select(item => {
index = item,
type = record.Type,
}))
.GroupBy(item => item)
.OrderByDescending(chunk => chunk.Count())
.Select(chunk => $"{chunk.index,-10} : {chunk.type,-10} {chunk.Count()}");
Console.WriteLine(string.Join(Environment.NewLine, result));
This is improve version or previous answers.
var pairs = Logs.SelectMany(x => x.IndexPattern.Split(',').Select(y => new {
Index = y, Type= x.Type }));
var pairs2 = (from p in pairs group p by p into grp select new { Index =
grp.Key.Index, Reason = grp.Key.Type, Count = grp.Count() }
).OrderByDescending(p => p.Count);
foreach (var i in pairs2)
{
//print with i
}

LINQ to SQL: Group, Count, Sum. I'm so confused

Good morning all,
I have been stuck on this all morning and feel like I've hit a wall. I'd love any advice that can be given at this point.
My table is basically as follows:
PatientName|LivingSpace
-----------|-----------
Patient 1 | Unit 1
Patient 2 | Unit 1
Patient 3 | Unit 2
Patient 4 | Unit 2
Patient 5 | Unit 3
Patient 6 | Unit 3
Patient 7 | Unit 3
Patient 8 | Unit 3
I need a LINQ to SQL query to illustrate this:
Unit|Count
----|-----
Unit 1 | 2
Unit 2 | 2
Unit 3 | 4
TOTAL | 8
My SQL query works fine, I'm just having issues with converting it to LINQ:
SELECT LivingSpace, COUNT(LivingSpace) AS LivingSpace
FROM PatientTable
WHERE Status = 'Active'
GROUP BY LivingSpace
UNION ALL
SELECT 'SUM' LivingSpace, COUNT(LivingSpace)
FROM PatientTable
var counts = from x in ctx.PatientTable
group x by x.LivingSpace into y
select new { Key = y.Key Count = y.Count() };
var total = new { Key = "Total" , Count = ctx.PatientTable.Count() };
var full = counts.ToList();
full.Add(total);
If you want to do it all in one query the following should work (adjusting for the actual names of your properties of course).
context.PatientTable.GroupBy(a => a.LivingSpace.Name, a => 1)
.Select(a => new
{
a.Key,
Total = a.Sum(q => q)
})
.Union(PatientTable.Select(a => new
{
Key = "Total",
Total = PatientTable.Count()
}))
var report = patients
.GroupBy(p => p.LivingSpace)
.Select(g => new
{
Unit = g.Key,
Count = g.Count()
})
.Union(patients
.Select(p => new
{
Unit = "Total",
Count = patients.Count
}));
Something like this should work and just run one query.
var results = db.PatientTable
.GroupBy(p => p.LivingSpace)
.Select(grp => new
{
Unit = grp.Key,
Count = grp.Count()
})
.Union(db.PatientTable
.GroupBy(p => 1)
.Select(grp => new
{
Unit = "Total",
Count = grp.Count()
}));
I see you got the answer, but for learning purposes, here is side by side conversion.
Your SQL (with some aliases added for better comparison)
SELECT P.LivingSpace, COUNT(P.*) AS Count
FROM PatientTable AS P
WHERE P.Status = 'Active'
GROUP BY P.LivingSpace
UNION ALL
SELECT 'SUM' AS LivingSpace, COUNT(P.*) AS Count
FROM PatientTable AS P
The same single query in LINQ
var query =
(
from p in db.PatientTable
where p.Status = "Active"
group p by p.LivingSpace into g
select new { LivingSpace = g.Key, Count = g.Count() }
)
.Concat
(
from p in db.PatientTable
group p by "SUM" into g
select new { LivingSpace = g.Key, Count = g.Count() }
);

Entity framework where, order and group

I'm using the following LINQ to select data from a table:
(from m in entity.Results
where m.Group == 0 ||
m.Group == 1
orderby m.Points descending
select m);
This gives me a result of all Users who are in Group 1 or 2. With that i can display the points they have. But this shows me the points they have in Group 1 and Group 2 separately.
How can i group them and display the total points they have? So instead of this (What i have now):
user1 - group1 - 10
user1 - group2 - 7
user2 - group1 - 7
user2 - group2 - 5
I want this:
user1 - total: 17
user2 - total: 12
How do i have to adjust my query to get a result set like that?
You need to group the users, then use Sum to calculate the TotalPoints:
from m in entity.Results
where m.Group == 0 || m.Group == 1
group m by m.User into g
let TotalPoints = g.Sum(m => m.Points)
orderby TotalPoints descending
select new { User = g.Key, Username = g.Key.Username, TotalPoints };
entity.Results
.Where(m => m.Group == 0 || m.Group == 1)
.GroupBy(m => m.UserID)
.Select(m => new { User = m.Key, TotalPoints = m.Sum(v => v.Points) })
.OrderByDescending(m => m.TotalPoints);
Hi Vivendi use this(Please edit according to your requirement)
var q = (from h in entity.Results
group h by new { h.UserID} into hh
select new {
hh.Key.UserID,
Score = hh.Sum(s => s.Points )
}).OrderByDescending(i => i.Points);
Output
total: 17
total: 12
Another example with more than one sum and a join
from e in _context.LearnResults
join c in _context.Country on e.CountryId equals c.CountryId
where c.DomainId.Equals("xx")
group e by e.Country.Name into newCountry
let Approved = newCountry.Sum(e => e.Approved)
let Total = newCountry.Sum(e => e.Total)
select new LearnResults() { CountryName = newCountry.Key, Approved= Approved, Total=Total };

Categories