I have a list of strings which I group by their occurrence in the list like following (where key is the list of those strings):
mostCommonKeywords = key.GroupBy(v => v)
.OrderByDescending(g => g.Count()) // here I get the count number
.Select(g => g.Key)
.Distinct()
.ToList();
The thing I want to do now is when they are sorted out, I wanna get their count, since LINQ can clearly distinguish their number and sort them out... How can I get the count occurrence of each string in the list now ???
Edit:
Let's say I have count values that look like this:
124
68
55
48
32
19
13
10
I cannot simply Add 1 of this value into a variable called "Count" as #octavioccl suggested. I clearly have to store them into some kind of list or something...
Using the Select and projecting in an anonymous type:
var result=key.GroupBy(v => v)
.Select(g => new {g.Key, Count=g.Count()})
.OrderByDescending(e => e.Count)
// .Distinct()// Don't need this call
.ToList();
Update
You can also project your query using a DTO:
public class CustomDTO
{
public string Key{get;set;} // Change the type in case you need to
public int Count{get;set;}
}
So, your query would be:
var result=key.GroupBy(v => v)
.Select(g => new CustomDTO{Key=g.Key, Count=g.Count()})
.OrderByDescending(e => e.Count)
.ToList();
from a in keys
group a by a.key into g
select new { a.Key, Count = g.Count() };
Related
I have the following result:
var result = (from p1 in db.Table
select new ReportInform
{
DataValue = p1.DataValue,
SampleDate = p1.SampleDate
})
.Distinct()
.ToList();
// Next getting list of duplicate SampleDates
var duplicates = result.GroupBy(x => x.SampleDate)
.Where(g => g.Count() > 1)
.Select (x => x)
.ToList();
foreach (var r in result)
{
if (duplicates.Contains(r.SampleDate)) // get error here on incompatbility
{
r.SampleDate = r.SampleDate.Value.AddMilliseconds(index++);
}
}
Cannot convert from 'System.DateTime?' to 'System.Linq.IGrouping
That error is pretty clear but may not be at a first glance. As a programmer, you need to learn how to read, understand and make sense of compiler or runtime errors.
Anyhow it is complaining that it cannot convert DateTime? to System.Linq.IGrouping<System.DateTime, ReportInForm>. Why? Because this query returns an System.Linq.IGrouping<System.DateTime, ReportInForm>
var duplicates = result.GroupBy(x => x.SampleDate)
.Where(g => g.Count() > 1)
.Select (x => x)
.ToList();
The GroupBy method returns IGrouping<System.DateTime, ReportInForm> which has a Key and the Key is the thing you grouped by and a list of items in that group. You are grouping by SampleDate and checking if there are more than one items in that group and then selecting the group. Thus dulplicates has a list of IGrouping<System.DateTime, ReportInForm> and you are asking the runtime to check if it contains a DateTime? and it blows up at this line:
duplicates.Contains(r.SampleDate)
One way to fix this is: What you want to do is to select the key of that group. Thus do this:
.Select (x => x.Key)
If you are expecting duplicates to be of type List<DateTime?> then you meant to write this
.Select(x => x.Key)
instead of
.Select(x => x)
This is an extension of already answered question by Jon Skeet that you can find here.
The desired result is following:
A 100
A 80
B 80
B 50
B 40
C 70
C 30
considering you have following class:
public class Student
{
public string Name { get; set; }
public int Grade { get; set; }
}
to get to the result (in ideal scenario) can be done with Jon Skeet's answer:
var query = grades.GroupBy(student => student.Name)
.Select(group =>
new { Name = group.Key,
Students = group.OrderByDescending(x => x.Grade) })
.OrderBy(group => group.Students.FirstOrDefault().Grade);
However in my case I have to support paging in my query as well. This means performing SelectMany() and then do Skip() and Take(). But to do Skip() you have to apply OrderBy(). This is where my ordering breaks again as I need to preserve the order I get after SelectMany().
How to achieve this?
var query = grades.GroupBy(student => student.Name)
.Select(group =>
new { Name = group.Key,
Students = group.OrderByDescending(x => x.Grade) })
.OrderBy(group => group.Students.FirstOrDefault().Grade).SelectMany(s => s.Students).OrderBy(something magical that doesn't break ordering).Skip(s => skip).Take(t => take);
I know I could manually sort again the records when my query is materialised but I would like to avoid this and do all of it in one SQL query that is translated from LINQ.
You can take another approach using Max instead of ordering each group and taking the first value. After that you can order by max grade, name (in case two students have the same max grade) and grade:
var query = c.Customers
.GroupBy(s => s.Name, (k, g) => g
.Select(s => new { MaxGrade = g.Max(s2 => s2.Grade), Student = s }))
.SelectMany(s => s)
.OrderBy(s => s.MaxGrade)
.ThenBy(s => s.Student.Name)
.ThenByDescending(s => s.Student.Grade)
.Select(s => s.Student)
.Skip(toSkip)
.Take(toTake)
.ToList();
All these methods are supported by EF6 so you should get your desired result.
Just re-index your list results and remove the index before returning.
var query = grades.GroupBy(student => student.Name)
.Select(group =>
new { Name = group.Key,
Students = group.OrderByDescending(x => x.Grade)
})
.OrderBy(group => group.Students.FirstOrDefault().Grade)
.SelectMany(s => s.Students)
.Select((obj,index) => new {obj,index})
.OrderBy(newindex => newindex.index)
.Skip(s => skip).Take(t => take)
.Select(final=> final.obj);
So far, I have this:
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x)));
Configuration folder will contain pairs of files:
abc.json
abc-input.json
def.json
def-input.json
GetReportName() method strips off the "-input" and title cases the filename, so you end up with a grouping of:
Abc
abc.json
abc-input.json
Def
def.json
def-input.json
I have a ReportItem class that has a constructor (Name, str1, str2). I want to extend the Linq to create the ReportItems in a single statement, so really something like:
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x)))
**.Select(x => new ReportItem(x.Key, x[0], x[1]));**
Obviously last line doesn't work because the grouping doesn't support array indexing like that. The item should be constructed as "Abc", "abc.json", "abc-input.json", etc.
If you know that each group of interest contains exactly two items, use First() to get the item at index 0, and Last() to get the item at index 1:
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x)))
.Where(g => g.Count() == 2) // Make sure we have exactly two items
.Select(x => new ReportItem(x.Key, x.First(), x.Last()));
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x))).Select(x => new ReportItem(x.Key, x.FirstOrDefault(), x.Skip(1).FirstOrDefault()));
But are you sure there will be exactly two items in each group? Maybe has it sence for ReportItem to accept IEnumerable, not just two strings?
So I have a List<Tuple<string, integer>>
A 10
A 11
B 12
B 13
And I want the following as a result
B 12
B 13
A 10
A 11
Basically I want to check which alphabet hold the highest value, in this case
B highest value is 13
A highest value is 11
That means B will have to run before A. But B hold 12 and 13, so it needs to be run in ascending order. So
B 12
B 13
then
A 10
A 11
Is this possible?
So I'll need something like
foreach row in list.OrderBy(//order condition)
{
//do something
}
UPDATE: Item2 is unique so the chance of 2 alphabet have the same value is not possible.
I think maybe this is what you're asking for:
list.GroupBy(x => x.Item1) // Group by Item1
.OrderByDescending(group => group.Max(x => x.Item2)) // Order the groups by the
// Max of Item2 (descending)
.Select(group => group.OrderBy(x => x.Item2)) // Order within the groups
// by Item2 (ascending)
.SelectMany(x => x) // Flatten the groups back into a single list
You can make this slightly more concise by combining the last two steps:
list.GroupBy(x => x.Item1) // group by Item1
.OrderByDescending(group => group.Max(x => x.Item2)) // Order the groups by Max(Item2)
.SelectMany(group => group.OrderBy(x => x.Item2)) // Order within groups and flatten
It seems that you need something like the following:
List<Tuple<string, int>> list = //getting your values
var result = list.GroupBy(x => x.Item1)
.Select(x => new
{
MaxValue = x.Max(y => y.Item2),
Items = x
})
.OrderByDescending(x => x.MaxValue)
.SelectMany(x => x.Items.OrderBy(y => y.Item2))
.ToList();
Grouping elements by Item1
Searching the maximum of each group and combining it into new instance
Ordering by max value desc, to place group with highest value on first place
Selecting result item, ordered by value ascending
result will contain required sequence
Is there some way in linq group By Id, Order By descending and then select top 5 of each grouping? Right now I have some code shown below, but I used .Take(5) and it obviously selects the top 5 regardless of grouping.
Items = list.GroupBy(x => x.Id)
.Select(x => x.OrderByDescending(y => y.Value))
.Select(y => new Home.SubModels.Item {
Name= y.FirstOrDefault().Name,
Value = y.FirstOrDefault().Value,
Id = y.FirstOrDefault().Id
})
You are almost there. Use Take in the Select statement:
var items = list.GroupBy(x => x.Id)
//For each IGrouping - order nested items and take 5 of them
.Select(x => x.OrderByDescending(y => y.Value).Take(5))
This will return an IEnumerable<IEnumerable<T>>. If you want it flattened replace Select with SelectMany