I want to get the count of each items in columns using LINQ GroupBy, however I don't get the expected output.
Example :
NAME | Items | Items2
1.ken | asd | zxc
2.kent | null | zwe
3.ken | qwe | null
Expected output:
NAME | Items | Items2
ken | 2 | 1
kent | 0 | 1
Code:
var Data = Items.GroupBy(z => z.Name)
.Select(s =>
new {
Name = s.Key,
Items = s.Count(q => q.Items),
Items2 = s.Count(x => x.Items2)
})
.ToList();
The above code does not work.
I think the null values create issues in Count() in the expected output. So I suggest you to add a condition in Count() to exclude null values. So your query will look like:
var Data = Items.GroupBy(z => z.Name)
.Select(s =>
new
{
Name = s.Key,
Items = s.Count(q => q.Items != null),
Items2 = s.Count(x => x.Items2 != null)
})
.ToList();
Related
The first query :
Id | UserId | projectId |date | Status
1 | 1 | 1 | 2020 | PENDDING
2 | 1 | 2 | 2020 | DONE
3 | 2 | 1 | 2020 | PENDDING
And what I tried two queries :
the first is about to get all userwork with X project for example id = 1
var FirstQery = context.table1.where (C => C.ProjectId == 1).count();
The second query is to fetch the number of user with project x have "done"status
var SecondQery = context.table1.where (C => C.ProjectId == 1 && C.Status == "DONE").count();
I want return object have only two values : countNumberUserWithXProject
and countNumberUserByXProjectHaveXStatus
It is known approach with fake grouping.
var query =
from t in context.table1
where t.ProjectId == 1
group t by 1 into g
select new
{
Count = g.Count(),
DoneCount = g.Sum(x => x.Status == "DONE" ? 1 : 0)
}
var result = query.FirstOrDefault();
How about returning an anonymous object (or if you like it more a typized object like a int[]).
return new {count1 = FirstQery , count2 = SecondQery };
(Return, or assign like var result = new {count1....} etc
You can also replace the FirstQuery and SecondQuery directly with the Linq query.
I need to take (for example, 2), 2 messages from a conversation
I dont care about how my list looks like, but i want only 2 messages from id 1, 2 messages from id2, and go on
example:
id = idConversation
Id | MessageId | Message
---|-----------|--------
1 | 1 | "asd"
1 | 2 | "asd2"
1 | 3 | "asd3"
1 | 4 | "asd4"
2 | 5 | "asd5"
3 | 6 | "asd6"
3 | 7 | "asd7"
3 | 8 | "asd8"
3 | 9 | "asd9"
3 | 10 | "asd10"
4 | 11 | "asd11"
4 | 12 | "asd12"
4 | 13 | "asd13"
and i want that
Id MessageId Message
---|-----------|--------
1 | 1 | "asd"
1 | 2 | "asd2"
2 | 5 | "asd5"
3 | 6 | "asd6"
3 | 7 | "asd7"
4 | 11 | "asd11"
4 | 12 | "asd12"
i can grouby idConversation, but i cant limit quantity using grouby in a conversation.
var test = unitOfWork.ChatMensagemRepository.GetAll()
.Where(x => x.PessoaCodigoPessoa == codigoRemetente)
.GroupBy(x => x.ChatConversaCodigoChatConversa)
.Select(group => new
{
codigoChat = group.Key,
list = group.Select(mensagem => new
{
// do stuff
})
}).ToList();
this is ok... but dont limit my list, when i do group.take(2).Select..... give me "Subquery returns more than 1 row"
var test = unitOfWork.ChatMensagemRepository.GetAll()
.Where(x => x.PessoaCodigoPessoa == codigoRemetente)
.GroupBy(x => x.ChatConversaCodigoChatConversa)
.Select(group => new
{
codigoChat = group.Key,
list = group.Take(2).Select(mensagem => new
{
// do stuff
})
}).ToList();
error : Subquery returns more than 1 row
var test = unitOfWork.ChatMensagemRepository.GetAll()
.Where(x => x.PessoaCodigoPessoa == codigoRemetente)
.GroupBy(x => x.ChatConversaCodigoChatConversa)
.Select(group => new
{
codigoChat = group.Key,
list = group.Select(mensagem => new
{
// do stuff
}).take(2)
}).ToList();
error : Subquery returns more than 1 row
It is caused, because EF provider for MySQL or server itself can't translate this linq to SQL, so you should at first get data from server and only then group it with Take(2):
var test = unitOfWork.ChatMensagemRepository.GetAll()
.Where(x => x.PessoaCodigoPessoa == codigoRemetente)
//this section is added
.Select(x => new
{
x.ChatConversaCodigoChatConversa,
x.prop1,//specify only columns, which you need for below code with Take
x.prop2
}).ToList()
//end of section
.GroupBy(x => x.ChatConversaCodigoChatConversa)
.Select(group => new
{
codigoChat = group.Key,
list = group.Take(2).Select(mensagem => new
{
mensagem.prop1,
mensagem.prop2
}).ToList()
}).ToList();
I want to get last user updated with a linq lambda expression using group by and the count of the remaining users. I don't know how I can do that.
here is my data :
userid | name | datetime | isdelete
1 | abc | 16-03-2017 15:45:59 | 0
1 | abc | 16-03-2017 12:45:10 | 0
2 | xyz | 16-03-2017 15:45:59 | 0
1 | abc | 16-03-2017 10:40:59 | 0
I want the result to look like this:
userid | name | datetime | count
1 | abc | 16-03-2017 15:45:59 | 3
2 | xyz | 16-03-2017 15:45:59 | 1
Here the count for userid = 1 should be 3 as there are three records for that id in the table.
I have written this query, but it is getting all the records.
List<Users> UList = new List<Users>();
UList = db.Users.Where(a => a.isdelete == false)
.OrderByDescending(a => a.datetime)
.Skip(skip)
.Take(pageSize)
.ToList();
Anyone know how I can get the data I want? Please let me know using linq lambda expression.
You need to group by user, than sort each group and take first from each group
var UList = (db.Users
.Where(a => a.isdelete == false)
.GroupBy(a => a.UserId)
.Select(g => new MyNewClass
{
Count = g.Count(),
User = g.OrderByDescending(a => a.datetime).First()
}
))
.Skip(skip)
.Take(pageSize)
.ToList();
You forgot to group your data:
var result = db.Users.Where(a => !a.isdelete)
.GroupBy(x => x.userid)
.Select(x => new User
{
userid = x.Key,
name = x.Last().Name,
datetime = x.OrderByDescending(a => a.datetime).First().datetime,
count = x.Count()
});
EDIT: This might be not optimal considering the performance as the call to Last and OrderByAscending will both iterate the whole data. To overcome this a bit you may re-structure this query a bit:
var result = db.Users.Where(a => !a.isdelete)
.GroupBy(x => x.userid)
.Select(x => new
{
user = x.OrderByDescending(a => a.datetime).First(),
count = x.Count()
})
.Select(x => new User {
name = x.user.name,
userid = x.user.userid,
datetime = x.user.datetime,
count = x.count
});
I've got the following data
title | useful
ttitle1 | Yes
ttitle1 | Yes
ttitle1 | No
ttitle2 | Yes
I would like to group the above data and flatten it so I get the following result:
Title | Useful Count | Not Useful Count
tttitle1 | 2 | 1
tttitle2 | 1 | 0
Tried this, but it does not produce the correct result:
var query = (from r in ratings
group r by new { r.ArticleTitle, r.Useful } into results
group results by new { results.Key.ArticleTitle } into results2
from result in results2
select new
{
Title = result.Key.ArticleTitle,
Yes = result.Select(i => i.Useful).Count(),
No = result.Select(i => i.Useful == false).Count()
});
Any help?
It seems to me that the only problem is that you're grouping twice. I'd expect this to work:
var query = from rating in ratings
group rating by rating.ArticleTitle into g
select new
{
Title = g.Key,
Yes = g.Count(r => r.Useful),
No = g.Count(r => !r.Useful)
};
Or not in query expression form:
var query = ratings.GroupBy(r => r.ArticleTitle,
(key, rs) => new
{
Title = key,
Yes = rs.Count(r => r.Useful),
No = rs.Count(r => !r.Useful)
});
You don't need to group twice to get the desired result. One Grouping would be fine:
var query = (from r in ratings
group r by new { r.ArticleTitle } into g
from result in groups
select new
{
Title = result.Key,
Yes = result.Select(i => i.Useful).Count(),
No = result.Select(i => !i.Useful).Count()
});
This is based on a previous question by Todilo.
The following accepted answer works great except I am required to return all records where type is null in addition to the latest for each type:
var query = Posts.GroupBy(p => p.Type)
.Select(g => g.OrderByDescending(p => p.Date)
.FirstOrDefault()
)
The scenario is as follows:
+----+--------------------------+-------+------------+
| id | content | type | date |
+----+--------------------------+-------+------------+
| 0 | Some text | TypeA | 2013-04-01 |
| 1 | Some older text | TypeA | 2012-03-01 |
| 2 | Some even older texttext | TypeA | 2011-01-01 |
| 3 | Sample | | 2013-02-24 |
| 4 | A dog | TypeB | 2013-04-01 |
| 5 | And older dog | TypeB | 2012-03-01 |
| 6 | An even older dog | TypeB | 2011-01-01 |
| 7 | Another sample | | 2014-03-06 |
| 8 | Test | | 2015-11-08 |
+----+--------------------------+-------+------------+
The result should be
Some text | TypeA
Sample |
A dog | TypeB
Another sample |
Test |
What about that:
var query = Posts
.GroupBy(p => p.Type)
.Select(g => g.OrderByDescending(p => p.Date).FirstOrDefault()).ToList()
var lostNullItems = Posts.Where(p => p.Type == null && !query.Contains(p));
var newQuery = query.Union(lostNullItems);
If you don't need the order of the items you can use:
var query = Posts
.GroupBy(p => p.Type)
.SelectMany(g =>
{
var result = g.OrderByDescending(p => p.Date);
return g.Key == null ? result ? Enumerable.Repeat(result.First(), 1);
});
This code is not tested.
Try code below. Because of the grouping the order isn't the same
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("id", typeof(int));
dt.Columns.Add("content", typeof(string));
dt.Columns.Add("type", typeof(string));
dt.Columns["type"].AllowDBNull = true;
dt.Columns.Add("date", typeof(DateTime));
dt.Rows.Add(new object[] { 0, "Some text", "TypeA", DateTime.Parse("2013-04-01")});
dt.Rows.Add(new object[] { 1, "Some older text", "TypeA", DateTime.Parse("2012-03-01")});
dt.Rows.Add(new object[] { 2, "Some older texttext", "TypeA", DateTime.Parse("2011-01-01")});
dt.Rows.Add(new object[] { 3, "Sample", null, DateTime.Parse("2013-02-24")});
dt.Rows.Add(new object[] { 3, "A dog", "TypeB", DateTime.Parse("2013-04-01")});
dt.Rows.Add(new object[] { 4, "And older dog", "TypeB", DateTime.Parse("2012-03-01")});
dt.Rows.Add(new object[] { 5, "An even older dog", "TypeB", DateTime.Parse("2011-01-01")});
dt.Rows.Add(new object[] { 4, "Another sample", null, DateTime.Parse("2014-03-06")});
dt.Rows.Add(new object[] { 5, "Test", null, DateTime.Parse("2015-11-08")});
var results = dt.AsEnumerable()
.GroupBy(x => x.Field<string>("type"))
.Select(x => x.Key == null ? x.ToList() : x.Select(y => new {date = y.Field<DateTime>("date"), row = y}).OrderByDescending(z => z.date).Select(a => a.row).Take(1))
.SelectMany(b => b).Select(c => new {
content = c.Field<string>("content"),
type = c.Field<string>("type")
}).ToList();
}
}
}
I'm thinking that a LINQ union is the only way to do it, primarily because of how you are sorting the output by date.
The first query should look like this:
var nullTypes = from p in Posts
where p.Type == null
select p;
The primary query should just filter out the nulls:
var query = Posts.Where(p => p.Type != null).GroupBy(p => p.Type)
.Select(g => g.OrderByDescending(p => p.Date)
.FirstOrDefault()
)
Union to your primary query:
var unionQuery = query.Union(nullTypes).OrderBy(p => p.Date);
The output will match what you are expecting, only that the first two lines will be inverted in terms of order:
Sample |
Some text | TypeA
A dog | TypeB
Another sample |
Test |
This is because the line item containing "Sample" has an older date than "Some text".
You shouldn't need to do any SelectMany - the original Select will projects a single item, so this works out into an IEnumerable that can fit the union.