I'd like to have an int property that is incremented for each item in group independently (as described here, because quotes need to be accessible like /person/quote/1..2..3 not /person/quote/1..5..10:
Quote Person Index
Lorem Smith 1
Ipsum Smith 2
Loremi Lewis 1
Ipsumi Lewis 2
Using code in that question with EF:
var query = _data.Quotes
.GroupBy(x => x.Person.Name)
.Select
(
x => x.Select((y, i) => new { y.Text, y.Person.Name, Index = i + 1 })
)
.SelectMany(x => x);
But EF cannot parse it and returns NotSupportedException exception:
LINQ to Entities does not recognize the method
System.Collections.Generic.IEnumerable`1[<>f__AnonymousType9`2[System.String,System.Int32]] Select[Quote,<>f__AnonymousType9`2](System.Collections.Generic.IEnumerable`1[App.Models.Quote], System.Func`3[App.Models.Quote,System.Int32,<>f__AnonymousType9`2[System.String,System.Int32]]) and this method cannot be translated into a store expression
Thanks to Dabblernl's comment this code is working:
var query = _data.Quotes
.GroupBy(x => x.Person.Name)
.ToList()
.Select
(
x => x.Select((y, i) => new { y.Person.Name, y.Text, Index = i + 1 })
)
.SelectMany(x => x);
Query:
var query = _data.Quotes
.GroupBy(x => x.Person.Name.ToLower())
.Select
(
x => x.Select((y, i) => new { y.Text.ToLower(), y.Person.Name.ToLower(), Index = i + 1 })
)
.SelectMany(x => x);
Related
var entity = await _abcRepository.get(Id);
var X = entity.GroupBy(c => c.number).Where(grp => grp.Count() == 1).Take(10).ToList();
in images you see [0] and inside of it one more [0].
How can I get that model value.
X[0][0] is not working.
X.Value is not working.
I need to convert that dictionary to model.
Use .Select to normalize aggregation as per your wish.
var X = entity.GroupBy(c => c.number).Where(grp => grp.Count() == 1)
.Select(group => new { GroupKey = group.Key, Items = group.ToList() })
.Take(10).ToList();
You could try something like this:
var entity = await _abcRepository.get(Id);
var results = entity.GroupBy(c => c.number)
.Where(grp => grp.Count() == 1)
.Take(10)
.ToDictionary(grp => grp.Key, grp => grp.First());
Essentially, the lambda you pass in Where method certifies that the groups are created contains only one item. That being said, you can use the First on each group to fetch that one element.
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);
Having this Linq query which returns grouping of 4 DateTime:
IEnumerable<IGrouping<DateTime, QuoteSnapshotModel>> lista = (from q in quoteModeList
where q.QuoteTradeType == "Q"
select q).GroupBy(n => n.ExceriseDate);
How can I order the groups by DateTime and get only the first group?
meaning **List<QuoteSnapshotModel>**
Also, how can I get only the second List<QuoteSnapshotModel> (according to DateTime)
Try this:
for this you have to create a list<QuoteSnapshotModel> within class QuoteSnapshotModel.
int record = 1;
List<QuoteSnapshotModel> result =
quoteModeList
.Where(x => x.QuoteTradeType == "Q")
.GroupBy(x => x.ExceriseDate,
(a, b) => new QuoteSnapshotModel
{
ExceriseDate = a,
ListQuoteSnapshotModel = b.ToList()
})
.OrderByDescending(t => t.ExceriseDate)
.Skip(record - 1).Take(1).ToList();
Update
You can use only the first group
List<QuoteSnapshotModel> list =quoteModeList.Where(x=>x.QuoteTradeType =="Q")
.GroupBy(x => x.ExceriseDate)
.OrderBy(x=>x.Key)
.FirstOrDefault().Select(x=>x.QuoteTradeType).ToList();
You can use only the second group
List<QuoteSnapshotModel> list =quoteModeList.Where(x=>x.QuoteTradeType =="Q")
.GroupBy(x => x.ExceriseDate)
.OrderBy(x=>x.Key)
.Skip(1).First().Select(x=>x.QuoteTradeType).ToList()
How can I order the groups by DateTime
.OrderBy(g => g.Key) or .OrderBy(g => g.First().ExerciseDate)
and get only the first group?
.First() (or .FirstOrDefault() if it's possible there are 0 groups)
how can I get only the second List (according to DateTime)
.Skip(1).Take(1) or .ElementAt(1) or .Skip(1).First()
Putting it all together:
IEnumerable<IGrouping<DateTime, QuoteSnapshotModel>> lista = (
from q in quoteModeList
where q.QuoteTradeType == "Q"
select q
).GroupBy(n => n.ExerciseDate);
IList<QuoteSnapshotModel> firstQuote = lista.OrderBy(x => x.Key).Select(x => x.ToList()).FirstOrDefault();
IList<QuoteSnapshotModel> secondQuote = lista.OrderBy(x => x.Key).Skip(1).Select(x => x.ToList()).FirstOrDefault();
I want to get the duplicate values count from one table. The input values are like as below,
SUB -xxx-20160721
SUB -xxx-20160721
SUB -125-20160022
Here (1) and (2) are same value. If the Name is more than 1 it should return 1 as a result. the result should return the count as (2).
var numberOfDuplicates = this.UnitOfWork.Repository<Models.SUB>()
.Queryable().GroupBy(x => x.Name)
.Where(x => x.Count() > 1)
.Select(x => x.Count());
The result is
2
2
2
2
2
3
2
2
4
Please guide me on this..
The return value of the below code is an anonymous object with 2 properties:
Value The value that is duplicate
Amount The amount of times it is duplicate
var numberOfDuplicates = this.UnitOfWork.Repository()
.Queryable().GroupBy(x => x.Name)
.Where(x => x.Count() > 1)
.Select(x => new { Value = x.Key, Amount = x.Count() } );
The problem with your code is that you're returning the Count of each group using the Select(x=> x.Count()) statement.
You can return the Name (The Key of Grouping) and the Count using anonymous types:
var numberOfDuplicates = this.UnitOfWork.Repository<Models.SUB>()
.Queryable().GroupBy(x => x.Name)
.Where(x => x.Count() > 1)
.Select(x => new { Name = x.Key, Count = x.Count() });
foreach(var dup in numberOfDuplicates)
{
Console.WriteLine($"Name = {dup.Name } ** Counter = {dup.Count}");
}
Results:
Name = 1.SUB -xxx-20160721 ** Count = 2
Dictionary<int, string> names= GetNames().Where(x =>
x.Value.StartsWith("test") | x.Value.StartsWith(" " + "test")).ToDictionary(x => x.Key, y => y.Value);
The values from the getNames() method are something like this:
John Testing
Test Travis
Test Metsaoy
Using the above line of code I'm getting only the two last entries, but I want also the 1st one because the 2nd string starts with "test".
So, I need to modify the above where statement. I tried something like this:
.Where(x =>
foreach ( xx in x.Value.Split(' ') ) { if ( xx.StartsWith("text") ) true; })
How can I achieve this?
var res = GetNames().Where(kvp => kvp.Value.Split()
.Any(s => s.StartsWith("Test") || s.StartsWith("test")));
Optionally instead of StartsWith you can use String.Contains in the Any lambda.
Try:
var parser = new Regex(#"\bTest", RegexOptions.Compiled);
GetNames().Where(x => parser.IsMatch(x.Value)).ToDictionary(x => x.Key, y => y.Value)
Have you tried this?
x.Value.StartsWith("test") || x.Value.Contains(" test")
You'll have to use it in your query like this:
var names= GetNames()
.Where(x => x.Value.StartsWith("test") || x.Value.Contains(" test"))
.ToDictionary(x => x.Key, y => y.Value);
Hope it helps