C# LINQ get count to dictionary - c#

I got a LINQ query with Entity Framework (EF) and getting a list of items. Now I want to create a dictionary with the incrementing index of the item and the item itself.
I have it like this:
result = context
.Items
.Where(b => !b.Deleted)
.OrderBy(b => b.Name)
.ToDictionary(COUNTHERE, b => b.Name)
So the dictionary have to look like this:
1: "item1"
2: "item2"
3: "item5"
4: "item10"
5: "item100"

I think what you need is to have the item name as the key instead the count as the key, because if there is two items that have the same count, it will throw exception that the key has been added.
Then you can Use GroupBy before ToDictionary so that you can count it.
result = context
.Items
.Where(b => !b.Deleted)
.GroupBy(x => x.Name)
.ToDictionary(g => g.Key, g => g.Count())
.OrderBy(g => g.Key);
based on your updated comment, then what you need is
result = context
.Items
.Where(b => !b.Deleted)
.OrderBy(b => b.Name)
.AsEnumerable()
.Select((v,i) => new { i, v.Name })
.ToDictionary(g => g.i + 1, g => g.Name);
Note that you need to add AsEnumerable so that the Select clause works as linq to object (Select that accept index is not supported in L2S).

Just use:
int count = 0;
var result = context
.Items
.Where(b => !b.Deleted)
.OrderBy(b => b.Name)
.ToDictionary(b => ++count, b => b.Name);

An alternative way of achieving this is:
var sortedNames = context
.Items
.Where(b => !b.Deleted)
.Select(b => b.Name)
.OrderBy(b => b.Name)
.ToArray();
result = Enumerable.Range(1, sortedNames.Length)
.ToDictionary(i => i, i => sortedNames[i - 1]);
To get zero-based numbering, use Enumerable.Range(0, sortedNames.Length) and sortedNames[i] instead.

Related

Linq get Distinct ToDictionary

need help to only select/get distinct entries based on i.Code.
There are duplicates and thus I'm getting an error in my expression "An item with the same key has already been added."
var myDictionary = dbContext.myDbTable
.Where(i => i.shoesize>= 4)
.OrderBy(i => i.Code)
.ToDictionary(i => i.Code, i => i);
Have tried to use Select and/or Distinct in different combinations and also by themselves but am still getting the same error
var myDictionary= dbContext.myDbTable
.Where(i => i.shoesize>= 4)
.OrderBy(i => i.Code)
//.Select(i => i)
//.Distinct()
.ToDictionary(i => i.Code, i => i);
Can anybody help? C#
UPDATE: If there are multiple objects with the same code I only want to add the first object(with that particular code) to myDictionary.
You can group by Code and select the first item from each group (which is equivalent to distinct):
var myDictionary = dbContext.myDbTable
.Where(i => i.shoesize >= 4) // filter
.GroupBy(x => x.Code) // group by Code
.Select(g => g.First()) // select 1st item from each group
.ToDictionary(i => i.Code, i => i);
You don't need the OrderBy since Dictionarys represent an unordered collection. If you need an ordered dictionary you could use SortedDictionary.
It sounds to me that what you are looking for is .DistinctBy() (available in .NET 6), which lets you specify which property to distinct the elements in your collection by:
var myDictionary= dbContext.myDbTable
.Where(i => i.shoesize>= 4)
.DistinctBy(i => i.Code)
.ToDictionary(i => i.Code, i => i);
By dividing it and creating a list first it worked as compared to when it was all bundled up into one linq, guess the First() needed it to be in a list before being able to make it into a dict.
var firstLinq = dbContext.myDbTable
.Where(i => i.shoesize>= 4)
.ToList();
then
var finalLinq = fromConcurWithDuplicates
.GroupBy(i => i.Code)
.Select(i => i.First())
.ToList()
.ToDictionary(i => i.Code, i => i);

How to take top 3 elements in each group using Entity Framework

I have the data in the source table.
And I want to get this kind of result in list using lambda expression and Entity Framework. I don't know how to do it. I need to get top 3 rows in for each CategoryId.
Probably using something like this:
context.GroupBy(x => x.CategoryId)
.Select(group => new {
CategoryId = group.Key,
NameId = group.Select(x => x.NameId),
group.OrderByDescending(e => e.Count).Take(3)
})
.ToListAsync()
var list = context
.GroupBy(x => x.CategoryId)
.SelectMany(group => group.OrderByDescending(e => e.Count).Take(3))
.OrderByDescending(e => e.Count)
.ToListAsync();
If you want an anonymous type:
var list = context
.GroupBy(x => x.CategoryId)
.SelectMany(group => group.OrderByDescending(e => e.Count).Take(3))
.Select(x => new
{
x.CategoryId,
x.NameId,
x.Count
})
.OrderByDescending(x => x.Count)
.ToListAsync();

Linq: GroupBy not show result for the .Include clause

Why in the result "Titolare" is null?
If I don't use GroupBy, "Titolare" has value.
Thank you.
var ben = context.Benefici.Include("Titolare").Include("Titolare.ComuneDomicilio")
.Where(b => !b.Titolare.SD1_DAT_DECESSO.HasValue)
.OrderByDescending(b => b.SDB_DAT_INIZIO)
.GroupBy(b => b.SDB_CODDIS)
.ToList()
.Select(b => b.First())
.ToList();
It is because of GroupBy limitation - you cannot get grouped items using LINQ to Entities. It should be fixed in EF Core 6.
To get first item of the group, you have to rewrite your query. It is mimic of what will be generated by EF Core 6:
var itemsQuery = context.Benefici
.Where(b => !b.Titolare.SD1_DAT_DECESSO.HasValue);
var benQuery =
from u in itemsQuery.Select(b => new { b.SDB_CODDIS }).Distinct()
join b in itemsQuery
.Include(x => x.Titolare.ComuneDomicilio)
.Where(x => x.SDB_CODDIS == u.SDB_CODDIS)
.OrderByDescending(x => x.SDB_DAT_INIZIO)
.Take(1)
select b;
var ben = benQuery.ToList();

Using LINQ ANY and occurrence > 1

I have a list of objects containing a collection of child objects. I want to check if any of these objects children contain a specific value AND if they do then check if this value appears in any other objects.
I currently have this which needs to be extended for the second check:
public bool HasAnyTypesMoreThanOnce(IEnumerable<Parent> parents, IEnumerable<string> Types)
{
return parents
.SelectMany(p => p.Children)
.Any(c => Types.Contains(c.Type));
}
I was thinking of something like this:
var list = parents
.SelectMany(p => p.children)
.Where(c => Types.Contains(c.Type))
.Select(c => c.Type).ToList();
return list.Count != list.Distinct().Count();
Any suggestions?
Another approach would be to group by Type and return true if theres any Type repeating more than once otherwise false.
return parents.SelectMany(p => p.children)
.Where(c => Types.Contains(c.Type))
.GroupBy(x => x.Type)
.Any(g => g.Count() > 1);
Maybe something like this
parents
.GroupBy(c => c.children.type)
.Where(grp => grp.Count() > 1)
.Select(grp => grp.children.type);

Getting Row Index for LINQ Query using Custom Object

I have the following LINQ query to receive indexes:
fieldIndexes = this.record.Fields.Where(a => !a.IsCodeField)
.OrderBy(a => a.DatabaseIndex)
.Select(a => a.DatabaseIndex - 1)
.ToArray();
But I want to replace the a.DatabaseIndex with the actual index of the search. I am aware of the syntax .Select((a, index) => new (index, a))... but I am not sure how to cast the a here to be of my type which in this case is Field. I have tried:
fieldIndexes = this.record.Fields.Select((a, index) => new {index, a})
.Where(a => !a.IsCodeField) // <- Invalid Cast.
.OrderBy(a => a.DatabaseIndex)
.Select(a => a.DatabaseIndex - 1)
.ToArray();
How can I cast a to my type within the LINQ statement?
Thanks for your time.
In the Where clause you are working with your newly created anonymous objects with properties a and index, which you can use:
.Where(a => !a.a.IsCodeField)
Of course this can be done in more readable fasion:
fieldIndexes = this.record.Fields.Select((a, index) => new {Index = index, Field = a})
.Where(a => !a.Field.IsCodeField)
...
You are projecting sequence items to anonymous objects with properties index and a. Original item will be accessible via property a:
fieldIndexes = this.record.Fields.Select((a, index) => new {index, a})
.Where(x => !x.a.IsCodeField)

Categories

Resources