I am currently getting error in my grouping logic. I am trying to sum the values in EMV for productnames that are same. I am getting error while passing only some list. How do I avoid this exception. I am not aware of doing null checks in linq experssion
System.ArgumentNullException: 'Value cannot be null. Parameter name: key'
Code
public Dictionary<string, decimal> SumProductEmv(IEnumerable<FirmWideAllocationsViewModel> allProducts)
{
if (allProducts == null)
return null;
return allProducts
.GroupBy(product => product.ProductName)
.Select(group => new
{
ProductName = group.Key, // this is the value you grouped on - the ProductName
EmvSum = group.Sum(item => item.Emv)
})
.ToDictionary(x => x.ProductName, x => x.EmvSum);
}
You could filter null or empty keys out using Where, try this:
return allProducts
.Where(product => !string.IsNullOrEmpty(product.ProductName))
.GroupBy(product => product.ProductName)
.Select(group => new
{
ProductName = group.Key, // this is the value you grouped on - the ProductName
EmvSum = group.Sum(item => item.Emv)
})
.ToDictionary(x => x.ProductName, x => x.EmvSum);
Also, you could Distinct() to prevent ArgumentException: An element with the same key already exists in the dictionary but then you need to decide which element you want to take, first, last, etc.
Related
Here's my code:
var groupedDataDictionary = products
.Where(p => p.ProductType == ProductType.ValueType)
.GroupBy(p => (p.OfficeDebitId, p.OfficeDebitDate, p.PaymentMethod))
.ToDictionary(x => x.Key, x => x.Sum(p => p.Amount));
var result = products.Select(p => new ResponseDto()
{
customer_id = p.CustomerId,
office_debit_date = p.OfficeDebitDate.Value.ToString(),
office_debit_id = p.OfficeDebitId.ToString(),
office_debit_total = groupedDataDictionary[new { p.OfficeDebitId, p.OfficeDebitDate, p.PaymentMethod }].Sum().ToString(), // this line causes error
payment_method = p.PaymentMethod.Value.ToString(),
}).ToList();
When assiging office_debit_total on that line it says:
Error CS1503 Argument 1: cannot convert from '<anonymous type: string
OfficeDebiId, System.DateTime? OfficeDebitDate,
Enumerations.PaymentMethod? PaymentMethod>' to '(string
OfficeDebitId, System.DateTime? OfficeDebitDate,
Enumerations.PaymentMethod? PaymentMethod)'
You should use either Tuples or Anonymous Types, but do not combine them. If you want to use Tuples for keys then you should also use Tuples to get dictionary values by keys:
var result = products.Select(p => new ResponseDto()
{
customer_id = p.CustomerId,
office_debit_date = p.OfficeDebitDate.Value.ToString(),
office_debit_id = p.OfficeDebitId.ToString(),
// Here you should use Tuple to get value by Key.
office_debit_total = groupedDataDictionary[(p.OfficeDebitId, p.OfficeDebitDate, p.PaymentMethod)].ToString(),
payment_method = p.PaymentMethod.Value.ToString(),
}).ToList();
Also note that I deleted invocation of the method Sum(), because dictionary groupedDataDictionary already contains aggregated data: x.Sum(p => p.Amount).
I'm trying to get the First and Latest record from a related entity using Linq lambda expression, but, I'm getting a invalid typecast error. Would you please tell me what am I doing wrong?
Here is the code
var all = DbContext.Players
.Include(g => g.GameDetails)
.GroupBy(x => new { x.Id, x.Name, x.IsActive})
.Select(x => new {
x.Key.Id,
x.Key.Name,
x.Key.IsActive,
FirstGameDate = x.Min( l => l.GameDetails.OrderByDescending( a => a.CreatedDate).First() ).CreatedDate ,
LastGameDate = x.Max( l => l.GameDetails.OrderBy( a => a.CreatedDate).Last() ).CreatedDate,
CreatedDate = x.Max( s => s.CreatedDate)
} );
.ToArray();
And the error:
Exception has occurred: CLR/System.InvalidCastException
"System.InvalidCastException"
'Unable to cast object of type
'SelectEnumerableIterator`2[Microsoft.EntityFrameworkCore.Storage.ValueBuffer,System.DateTime]' to type 'System.DateTime'.'
I have the following table structure. I want to retrieve value corresponding to key for each group name and insert it store it sequentially in a model class
the table data has been read using a ExecuteQuery and stored in a list of class object, in the below example I will have 4 rows returned. I need to convert it into 2 rows, the column values coming in as rows.
I have the following code written now, But is there any other way to verify it without explicitly checking for say Key == "GroupSpecificProperty1"?
If there is a 3rd category added later, I shouldn't have to modify this code
Result = results.GroupBy(p => p.GroupName )
.Select(g => new FinalModel()
{
GroupName = g.Select(p => p.GroupName ).FirstOrDefault(),
GroupSpecificProperty1 = g.Where(q => q.Key == "GroupSpecificProperty1").Select(v => v.Value).Cast<string>().FirstOrDefault(),
GroupSpecificProperty2= g.Where(q => q.Key == "GroupSpecificProperty2").Select(v => v.Value).Cast<string>().FirstOrDefault(),
}).ToList();
results.GroupBy(p => p.GroupName)
.Select(g => new FinalModel
{
GroupName = g.Key,
Properties = g.ToDictionary(item => item.Key, item=> item.Value)
});
And in the case that for a given GroupName the keys are not unique and you'd want to avoid a "key already exists" exception then you can:
results.GroupBy(p => p.GroupName)
.Select(g => new FinalModel
{
GroupName = g.Key,
Properties = g.GroupBy(item => item.key)
.ToDictionary(innerGroup => innerGroup.Key,
innerGroup => innerGroup.Select(innerItem => innerItem.Value))
});
Then of course you can also replace the outer/inner dictionary with a LookUp if it fits your needs better.
I have a list of int? that can have 3 different values: null, 1, and 2.
I would like to know which of them occurs the most in my list. To group them by value I tried to use:
MyCollection.ToLookup(r => r)
How can I get the value with most occurrence?
You don't need a Lookup, a simple GroupBy would do:
var mostCommon = MyCollection
.GroupBy(r => r)
.Select(grp => new { Value = grp.Key, Count = grp.Count() })
.OrderByDescending(x => x.Count)
.First()
Console.WriteLine(
"Value {0} is most common with {1} occurrences",
mostCommon.Value, mostCommon.Count);
I'm trying to query a view (entity) from the database and return back a dictionary. There are duplicates in the view so I tried groupby and I can't figure it out.
var queryresults = db.MyView.Where(x => x.year == myYear)
.GroupBy(g => new { g.myCode, g.myCodeName})
.ToDictionary(d => d.myCode, d => d.myCodeName);
You should group by dictionary key property if you want to avoid duplicate keys error. Then you can select code name of first item in each group as dictionary entry value:
var queryresults =
db.MyView.Where(x => x.year == myYear)
.GroupBy(x => x.myCode)
.ToDictionary(g => g.Key, g => g.First().myCodeName);