Please consider this table:
id Name Year Val1 Val2
-------------------------------------------------------------
1 Japan 2010 20 a
2 Korea 2010 10 a
3 Japan 2010 10 b
4 Germany 2011 22 a
5 Austria 2012 18 a
6 Austria 2012 17 m
7 Germany 2013 11 j
8 Germany 2013 12 j
I want to select records that have just 1 record in a year. This is my desire result:
id Name Year Val1 Val2
------------------------------------------------------------
2 Korea 2010 10 a
4 Germany 2011 22 a
How can I do this with LINQ. Thanks
Make group of records with same [Name, Year] combination, and throw away all groups that have more than one element:
var countries1Record = originalRecords.GroupBy(
record => new
{
Country = record.Name,
Year = record.Year,
})
.Where(group => group.Skip(1).Any())
.Select(group => group.FirstOrDefault());
I use Skip(1).Any() instead of Count() == 1, because it is more efficient: why count all 1000 records, if you can stop counting after the first record?
The final Select selects the one-and-only record in the group
You would need to do a Grouping with a 'Having' clause. The code below should help or point you in the right direction.
var data = new List<Data>();
//Method syntax:
var row = data.GroupBy(k => new { k.Year, k.Name}, v => v)
.Where(grp => grp.Count() == 1)
.SelectMany(o => o)
.ToList();
//Query syntax:
var row2 = (from d in data
group d by new {d.Year, Name = d.Name}
into g
where g.Count() == 1
select g)
.SelectMany(o => o)
.ToList();
Added grouping by Name & Year and Query Syntax. Just a note: Both Query & Method Syntax is linq. Just different ways of writing it.
Hope this helps
Assuming your data is stored in rows:
var results = rows.Where(r1 => !rows.Any(r2 => r1.Name == r2.Name && r1.Year == r2.Year && r1.Id != r2.Id));
Related
I have a list with set of values. I wanted to check if the table has the matching values with the matching count using a LINQ query in c#
This is my list:
List<int> list1 = new List<int>()
{
130011,
130010
};
This is my table
RelEmployeeDepartments:
ID EmpID DeptID
8 4 130011
9 4 130010
10 4 2
18 13 130011
19 13 130010
20 13 1
21 13 2
23 5 130011
24 5 130010
Now i wanted to find all the Employee's who are already assigned to the exact departments list1 has along with the same count. So with the values in my list1 the output shall be EmpID 5 as it has the same values and same count of departments. EmpID 4 & 13 shouldn't be in my output because even though there are matching departments for the employee, the count is different.
This is the working SQL query i came up with:
SELECT EmpID FROM
RelEmployeeDepartments WHERE EmpID IN
(SELECT red.EmpID FROM RelEmployeeDepartments red
GROUP BY red.EmpID HAVING COUNT(red.DeptID) = 2)
AND DeptID IN (130010,130011)
GROUP BY EmpID HAVING COUNT(DeptID) = 2
I managed to get the inner query with LINQ like this but couldn't convert it fully.
var innerQuery = (from red in RelEmployeeDepartments
group red by red.EmpID into red1
where red1.Count().Equals(list1.length)
select red1.Key);
I am wondering how can i convert this to a LINQ query or if there is even a better solution than above one?
you could use a combination of Contain, GroupBy, and Where clauses:
var result = RelEmployeeDepartments
.Where(e => list1.Contains(e.DeptID))
.GroupBy(g => g.EmpId)
.Where(grp => grp.Count() == list1.Count())
above will give you IGrouping, you can then Select and SelectMany to get IEnumerable<int> of EmpID
result.Select(grp => grp.Select(v => v.EmpId)).SelectMany(x => x).Distinct()
Finally after lot of struggle,help with #farzan-mirheydari answer and Using linq to group a table that contains substrings this is my working solution.It's an exact conversion of my SQL query in the question
from red1 in RelEmployeeDepartments
where
(from red in RelEmployeeDepartments group red by new {
red.EmpID
}
into g where g.Count() == list1.Count() select new {
g.Key.EmpID
}).Contains(new {
EmpID = red1.EmpID
}) &&
(list1).Contains(red1.DeptID)
group red1 by new {
red1.EmpID
}
into g
where g.Count() == list1.Count()
select new {
g.Key.EmpID
};
Lambda Code:
RelEmployeeDepartments
.Where(
red1 =>
(RelEmployeeDepartments
.GroupBy(
red =>
new {
EmpID = red.EmpID
}
)
.Where(g => (g.Count() == list1.Count()))
.Select(
g =>
new {
EmpID = g.Key.EmpID
}
)
.Contains(
new {
EmpID = red1.EmpID
}
) &&
list1.Contains(red1.DeptID)
)
)
.GroupBy(
red1 =>
new {
EmpID = red1.EmpID
}
)
.Where(g => (g.Count() == list1.Count()))
.Select(
g =>
new {
EmpID = g.Key.EmpID
}
);
I know it looks complex. If there is a better or easier way, please post it.
I have a simple scenario for which i want to write LINQ query, But i am unable to get it right. Here is the scenario:
I have 3 Tables:
STUDENT:
--------------------------
SID Name
---------------------
1 Jhon
2 Mishi
3 Cook
4 Steven
COURSE:
-------------------
CID Name
-------------------
1 Maths
2 Physics
3 Bio
4 CS
STUDENTCOURSE:
---------------------------
SCID SID CID
-----------------------
1 1 1
2 1 2
3 1 4
4 2 1
5 2 2
6 2 3
7 3 1
8 3 4
10 4 2
For this case i want to pass array of course ids to query and return all student those have all the these courses registered against them. What i tried:
int[] cIds = {1,2,4 };
var result = from s in context.Students
where s.StudentCourses.Any(sc=> cIds.Contains(sc.CID))
select s;
But this returns students those registered either of the course id 1,2,4.
Hope you understand my problem.
Thanks for the help.
Try the following:
int[] cIds = {1,2,4 };
var result = from s in context.Students
where cIds.All(id => s.StudentCourses.Any(sc=> sc.CID == id))
select s;
Use this:
int[] cIds = {1,2,4 };
var q = context.StudentCourses.Join(context.Students,
x => x.SId,
x => x.Id,
(sc, s) => new { Student = s, CourseId = sc.CId })
.GroupBy(x => x.Student.Id)
.Where(sc => cIds.All(cid => sc.Any(y => y.CourseId == cid)))
.Select(x => x.FirstOrDefault().Student)
.ToList();
Or if you prefer linq query:
int[] cIds = {1,2,4 };
var q2 = (from s in context.Students
join sc in context.StudentCourses on s.Id equals sc.SId into sCources
where cIds.All(id => sCources.Any(y => y.CId == id))
select s).ToList();
Here is a fiddle for it, using linq-to-objects.
Edit:
I didn't notice that in your model there is a navigation property from Student to StudentCourse, in this case the query will be much simpler and does not need join, and Patrick's answer works perfectly.
I am struggling with Linq, hence it is a lame question but still ..
I have a table with following 4 columns
Pid SKU colorid sizeid
1 'A65102' 38 2
2 'A65102' 38 4
3 'A65102' 38 18
I have to get how many different color and size option are available for this.
In sql, I use to do it by:
select count(distinct [sizeid]) ,count(distinct [colors])
from [item_master]
where sku = 'A65102'
But in Linq, I can get all the values by
var dd = (from im in db.item_masters
where im.sku.Contains("A65102")
select new {im.sizeid,im.colors });
But how can I get the count of distinct values for both in single query?
You could use GroupBy:
var distinctCounts = db.item_masters.GroupBy(im => im.sku)
.Where(grp => grp.Key == "A65102")
.Select(grp => new {
CntSizes = grp.Select(im => im.sizeid).Distinct().Count(),
CntColors = grp.Select(im => im.colorid).Distinct().Count()
});
You can use the query that you have as a data source for retrieving this data (especially useful if you would want to use it for other things as well afterwards):
var dd = (from im in db.item_masters
where im.sku == "A65102"
select new {im.sizeid, im.colors}).ToList();
var numDistinctSizes = dd.Select(x => x.sizeid).Distinct().Count();
var numDistinctColors = dd.Select(x => x.colors).Distinct().Count();
Considering the following records:
Id F1 F2 F3
-------------------------------------------------
1 Nima 1990 10
2 Nima 1990 11
3 Nima 2000 12
4 John 2001 1
5 John 2002 2
6 Sara 2010 4
I want to group by based on the F1 field and sort by Id and get all fields from the first record of group similar to these records:
Id F1 F2 F3
-------------------------------------------------
1 Nima 1990 10
4 John 2001 1
6 Sara 2010 4
How can I do this using linq?
var result = input.GroupBy(x => x.F1, (key,g) => g.OrderBy(e => e.F2).First());
var res = from element in list
group element by element.F1
into groups
select groups.OrderBy(p => p.F2).First();
The awnser of #Alireza is totally correct, but you must notice that when using this code
var res = from element in list
group element by element.F1
into groups
select groups.OrderBy(p => p.F2).First();
which is simillar to this code because you ordering the list and then do the grouping so you are getting the first row of groups
var res = (from element in list)
.OrderBy(x => x.F2)
.GroupBy(x => x.F1)
.Select()
Now if you want to do something more complex like take the same grouping result but take the first element of F2 and the last element of F3 or something more custom you can do it by studing the code bellow
var res = (from element in list)
.GroupBy(x => x.F1)
.Select(y => new
{
F1 = y.FirstOrDefault().F1;
F2 = y.First().F2;
F3 = y.Last().F3;
});
So you will get something like
F1 F2 F3
-----------------------------------
Nima 1990 12
John 2001 2
Sara 2010 4
Use it to achieve what you want. Then decide which properties you want to return.
yourList.OrderBy(l => l.Id).GroupBy(l => new { GroupName = l.F1}).Select(r => r.Key.GroupName)
var res = (from element in list)
.OrderBy(x => x.F2).AsEnumerable()
.GroupBy(x => x.F1)
.Select()
Use .AsEnumerable() after OrderBy()
Another way:
var result = input.GroupBy(i => i.F1).Select(g => g.First());
You can group by multiple fields:
var result = input.GroupBy(i => new {i.F1, i.F2}).Select(g => g.First());
If you need keep order, then use lookup:
var result = input.ToLookup(i => i.F1).Select(g => g.First());
It's not exactly what you were looking for, but sometimes we look for the wrong thing because we don't know what exists. So my solution I find the most intuitiv:
var dict =
input.OrderByDescending(x => x.Id)
.GroupBy(x => x.F1)
.ToDictionary(x => x.Key, x => new { x.First().F1, x.First().F2, x.First().F3});
First order, then group – straight forward. Now the result of that will be a list of key-type pairs❊. As our table was already sorted, we can just pick the first entry. Also I advise to put the result in a dictionary with the ID as accessor, it's a very fast data structure to access and still flexible. Now you can access it using
dict[4].F1 // returns Nima
❊ technically its IEnumerable<IGrouping<int, yourType>>
If I have a list of an object called Spendline with two properties, Year and Amount and BudgetID. How can I best convert the following List:
Year Amount BudgetID
2000 100 1
2001 100 1
2002 100 1
2003 100 1
2001 100 2
2002 100 2
2003 100 2
To this:
Year Amount
2000 100
2001 200
2002 200
2003 200
Using Linq?
Looks like you want something like:
var query = items.GroupBy(x => x.Year, x => x.Amount)
.Select(g => new { Year = g.Key, Amount = g.Sum() };
Or as a query expression:
var query = from item in items
group item.Amount by item.Year into g
select new { Year = g.Key, Amount = g.Sum() };
(Call ToList on the query to get a List<T> of course.)
I think you can do this with GroupBy and Sum functions
An example of getting this data with a loop might look like this:
foreach(var group in SpendlineList.GroupBy(x => x.Year))
{
int year = group.Key;
int ammount = group.Sum(x => x.Ammount);
}