var aaa = data.GroupBy(o => o.Date).Select(o => new { o }).ToList();
var bbb = aaa.Select(o => o.Key).ToList();
//There is a error of `Key`
Does that mean the Key is only allowed for the original List after GroupBy. Is it possible to obtain the Key for any Select after GroupBy?(Surely, we can storge the Key = o.Key in the Select )
Furthermore,
var aaa = data.GroupBy(o => o.Date).Select(o => o.ToList()}).ToList();
If we change aaa into two dimensional List, Is it possible to obtain the previous Key?
In your first linq expression, in the Select you are wrapping the IGrouping object that you got from the GroupBy with a new anonymous object.
So to get that Key property in your second line you should:
//Original:
var bbb = aaa.Select(o => o.Key).ToList();
//Change to:
var bbb = aaa.Select(o => o.o.Key).ToList();
For second question, if you want to get the Key in this case:
//Original:
var aaa = data.GroupBy(o => o.Date)
.Select(o => o.ToList()})
.ToList();
//Then you should:
var aaa = data.GroupBy(o => o.Date)
.Select(o => o.ToList()})
.Select(x => o.FirstOrDefault().Date)
.ToList();
Reason being is that:
You group your items by Date
First select you convert a IGrouping into a List<YourClass> but now you have an IEnumerable<List<YourClass>> where each record in the IEnumerable, all the inner items will have the same date
In second Select - take whichever item in the inner collections - and get the Date it is the same as getting the Key in the example before
To achieve what you actually what to get (grouping by the date and getting for each group the symbols):
var result = data.GroupBy(item => item.Date)
.Select(group => new { group.Key, Symbols = group.Select(item => item.Symbol).ToList() });
//Or using a different overload of the `GroupBy`:
var result = data.GroupBy(item => item.Date,
(key,group) => return new { Key = key, Symbols = group.Select(item => item.Symbol).ToList() });
Problem is your incorrect syntax. You crated an anonymous object, so you need to access the property with instance name. So you should be doing this.
var bbb = aaa.Select(o => o.o.Key).ToList();
if we change aaa into two dimensional List, Is it possible to obtain
the previous Key?
No, because you have groped values collection not the Key. So result will not contain Key.
Related
So I have a table like this:
Now I want distinct ShortCode order by the ID descending. In other words, the distinct last records. Like this:
So I tried GroupBy like:
var data = db.ShortCodes.GroupBy(x => x.ShortCode).Select(x => x.FirstOrDefault()).OrderByDescending(s=> s.ID);
This gave me distinct records but not the last ones, nor ordered by ID descending:
Now I also tried like suggested here
var data = db.ShortCodeManager
.GroupBy(s => s. ShortCode)
.Select(g => g.First())
.OrderByDescending(s => s.ID);
This gave me the error The method 'First' can only be used as a final query operation. Consider using the method 'FirstOrDefault' in this instance instead.
So I modified to FirstOrDefault() like:
var data = db.ShortCodeManager
.GroupBy(s => s. ShortCode)
.Select(g => g.FirstOrDefault())
.OrderByDescending(s => s.ID);
This also gave me distinct records but not the last records:
So finally I tried like suggested here:
var data = db.ShortCodeManager.Where(a => a.ID > 0).GroupBy(x => x.ShortCode).OrderByDescending(grp => grp.Max(g => g.ID)).Select(a => a.FirstOrDefault());
Again, this gave me distinct records but not the last ones, nor ordered by ID descending:
So how am I to write the query to get the result I want in Linq? Also note, I need more of the distinct last records than ordering by ID descending. If anyone also knows how to write it in raw SQL it might be useful as well.
This LINQ query should work for your case:
var result = db.ShortCodeManager
.GroupBy(x => x.ShortCode)
.Select(gr => new { Id = gr.Max(g => g.Id), ShortCode = gr.Key})
.ToList();
EDIT:
Based on your comment it looks like you need to cast anonymous object result to ShortCodeManagerModel type and then pass it to your view. So, somethin like this:
var result = db.ShortCodeManager
.GroupBy(x => x.ShortCode)
.Select(gr => new { Id = gr.Max(g => g.Id), ShortCode = gr.Key})
.ToList();
var model = result
.Select(x => new ShortCodeManagerModel { Id = x.Id, ShortCode = x.ShortCode })
.ToList();
And then pass model to you view.
I have a linq Query
var tListOfDates = tList.GroupBy(g => g.dateOfSlot)
.Select(s => new {s.Key.Value });
dateOfSlot is a DateTime value
How can I convert tListOfDates to IEnumerable<DateTime>
I've tried top cast the result, but it doesn't work.
You should drop anonymous class new {s.Key.Value } (you don't want it but DateTime):
var tListOfDates = tList
.GroupBy(g => g.dateOfSlot)
.Select(s => s.Key.Value);
It seems that dateOfSlot is of type DateTime?, not DateTime since you put s.Key.Value, not s.Key; if my guess is right you can put it as
var tListOfDates = tList
.Where(item => item.dateOfSlot.HasValue)
.Select(item => item.dateOfSlot.Value)
.Distinct();
A proposition,you take all dates and get the unique date by Distinct
var tListOfDates = tList.Select(g => g.dateOfSlot).Distinct();
I Solved with
IEnumerable<DateTime> tListOfDates = tList.Where(w => w.dateOfSlot.HasValue).Select(g => g.dateOfSlot).Distinct().ToArray().Cast<DateTime>();
May be there is something more that needed and the query can be simplified.
So you have an object tlist, which implements IEnumerable<MySlot>. We don't know a lot of MySlot, yet we know that every MySlot object has a DateTime property DateOfSlot.
The first part of your LINQ statement groups all MySlots in your tlist into groups of MySlots where every MySlot in the group has equal DateOfSlot:
tList.GroupBy(mySlot => mySlot.dateOfSlot)
Every group has a Key which contains this common DateOfSlot. So the Key is d DateTime object
The second part projects every group into one element:
.Select(group => new {group.Key.Value });
group.Key is a DateTime. The problem is that a Datetime does not have a property Value. Are you sure that DateOfSlot is a DateTime?
It's not entirely certain what you want.
I have an IEnumerable<MySlot> in tList, and I want all used DateOfSlot values in this list
var allUsedDateOfSlotValues = tList.Select(mySlot => mySlot.DateOfSlot);
But now I have duplicates, I don't want duplicates!
var allDistinctUsedDateOfSlotValues = tList
.Select(mySlot => mySlot.DateOfSlot)
.Distinct();
This will have the same result as your code:
var result = tList.GroupBy(mySlot => mySlot.DateOfSlot)
// result: groups of mySlots with same DateOfSlot
.Select(group => group.Key)
// result: distinct values of DateOfSlot
I have a list where I'm applying the following condition with linQ:
I want to select all items where Name contains a certain string.
var nameFilter = result
.Where(e => e.Name.Contains(requestedValue))
.ToList();
At the end, sometimes it happens that I am having a list with repeated names:
For example:
requestedValue = 'form';
I end up with:
Name Price
transformer 100
transformer 20
formation 340
former 201
I got transformer twice. In that case, I want to only leave transformer with the least price : 20
How could I do this with linQ without looping?
You can take advantage of GroupBy method
var nameFilter = result.Where(e => e.Name.Contains(requestedValue))
.GroupBy(k=>k.Name, g=>g.Price, (k,g)=>new Model {Name = k, Price = g.Min()})
.ToList();
where new Model should be changed to your class name.
If you have more properties to return probably it will be more convenient to do
var nameFilter = result.Where(e => e.Name.Contains(requestedValue))
.GroupBy(k => k.Name, g => g, (k, g) =>
{
var minPrice = g.Min(x => x.Price);
return g.First(x => x.Price == minPrice);
}).ToList();
Finding minPrice and finding the item with minPrice can be done is a single for loop or, for example, by using following discussion here
I have the following dataset, which is stored in a variable called list1.
countrypk | countryname | statepk | statename
---------------------------------------------
1 USA 1 New York
1 USA 2 California
2 Canada 3 Manitoba
I want to be able to group by countrypk, and retrieve the country name.
I have the following LINQ that achieves that effect, but was wondering if there was a better or more straight forward way to do it in LINQ.
var finalList = list1
.GroupBy(item => item.countrypk)
.Where(item => item.Count() > 0)
.Select(item => item.First())
The desired output is:
countrypk | countryname
---------------------------------------------
1 USA
2 Canada
The addition of the Where is not needed. If you have a group it contains at least a single item in it. You can do something like this:
list1.GroupBy(item => item.countrypk)
.Select(item => new { item.Key, item.First().countryname} );
Or using a different overload of GroupBy:
list1.GroupBy(item => item.countrypk,
selector => new { selector.countrypk, selector.countryname} )
.Select(group => group.First())
If you grouped by countrypk, your result set wouldn't have duplicates in it. Your desired result set has duplicate countrypk values in it (1). To get your desired result set, do this:
var finalList = list1.Select(s => new { s.countrypk, s.countryname });
Edit: nevermind this part above, OP editted the question.
I want to be able to group by countrypk, and retrieve the country name What you're asking for is different than what your result set shows. If you want a map of countrypk to country name using your list1, here's one way to do it:
var finalList = list1
.GroupBy(g => new { g.countrypk, g.countryname })
.ToDictionary(k => k.Key.countrypk, v => v.Key.countryname);
Note that you don't need GroupBy to do this. Here's another solution:
var finalList = list1
.Select(s => new { s.countrypk, s.countryname })
.Distinct()
.ToDictionary(k => k.countrypk, v => v.countryname);
In either case, to get the country name for id 1, do this:
var countryName = finalList[1];
Try the following
var finalList = list1
.GroupBy(item => item.countrypk)
.Select(g => new { countrypk = g.Key, countryname = g.First().countryname });
which should provided the desired output
Basically you want to remove duplicates by countrypk and select only first two columns? Use this extension:
public static IEnumerable<TSource> DistinctBy<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
HashSet<TResult> set = new HashSet<TResult>();
foreach(var item in source)
{
var selectedValue = selector(item);
if (set.Add(selectedValue))
yield return item;
}
}
And then
var finalList = list1
.DistinctBy(item => item.countrypk)
.Select(item=> new {item.countrypk, item.countryname })
.ToList();
If I have a set of entities with 3 properties (Id, Type, Size) all of which are strings.
Is there a way using Linq to Entities where I can do a group query which gives me the Size + Type as the key and then a list of the related Id's for that Size + Type?
Example below of getting the count:
Items.GroupBy(x => new { x.Size, x.Type})
.Select(x => new { Key = x.Key, Count = x.Count() })
but I am looking to get a list of the Ids for each grouping?
I am looking to see if it is possible using Linq-to-EF before I decide to iterate through this in code and build up the result instead.
If you want to get List of Ids for each group then you have to select x.Select(r => r.Id) like:
var result = Items.GroupBy(x => new { x.Size, x.Type })
.Select(x => new
{
Key = x.Key,
Ids = x.Select(r => r.Id)
});
Another way to build up a Dictionary<string, IEnumerable<string?>> in dotnet 6.0 according to the docs;
where we have the dictionary Key as {Size, Type} and Value the list of Ids, you can write:
Dictionary<string, IEnumerable<string?>> result = Items.GroupBy(item => new { item.Size, item.Type }
item => item.Id),
(itemKey, itemIds) =>
{
Key = itemKey,
Ids = itemIds
})
.ToDictionary(x => x.Key, x=> x.Ids);