Dictionary cannot convert from '<anonymous type>' - c#

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).

Related

How to concat string in LinQ group

var list = Table
.GroupBy(t => t.GroupId, (key, g) => new {key, g})
.Select(t => new Transaction
{
Date = t.g.First().DateCreate,
Reference = $"{t.g.First().AccounttName} {t.g.Select(z => z.DocumentNo)}",
TotalAmount = t.g.Sum(x => x.y.Amount.Value),
})
When grouping with linQ I know how to get a single value with First(), sum with Sum() but what should I do to concact a string value?
In my example how can I merge all my DocumentNo?
Use string.Join:
Reference = $"{t.g.First().AccounttName} {string.Join(",",t.g.Select(z => z.DocumentNo))}"

Store value in dictionary or retrieve from concatened key

I have a dictionary that aggregates the same items and sum a specific value from:
var test = list.GroupBy(x => new { ID=x.ItemID, Uti=x.UtilityName })
.ToDictionary(x => x.Key,
x => x.Sum(t => Convert.ToDecimal(t.EnergyConsumptionQt)
));
This returns a dictionary with a key value that is a concatenation of string ID and string Uti.
I would like to either:
Create a Dictionary<string, decimal> in which the key is the combination / concatenation ItemID+UtilityName (ID + Uti), or a way to get the values from the test variable above, as the current one I do not know how to specify the value I want from as everything that I try returns: cannot convert 'X' to ''.
Do it this way:
var test = list.GroupBy(x => new { ID=x.ItemID, Uti=x.UtilityName })
.ToDictionary(x => x.Key.ID.ToString()+x.Key.Uti,
x => x.Sum(t => Convert.ToDecimal(t.EnergyConsumptionQt)
));
The problem with your initial approach is that the annonymous type is a reference type so the dictionary uses the reference as a key (rather than the values you want to be combined).
As such if you subsequently try to accesss an element with for example:
var elem = test[new {ID=1, Uti="myUtiName"}]
then you actually create a NEW object which does not exist in test so you would get a KeyNotFoundException thrown.
If you use a value type for your dictionary key instead then the dictionary will behave as you are expecting. Perhaps have a struct - something like this maybe:
struct DictKey
{
public string UtilityName { get; set; }
public int Id { get; set; }
}
then your test variable can be initialised with:
var test = list
.GroupBy(x => new DictKey { Id=x.ItemID, UtilityName=x.UtilityName })
.ToDictionary(x => x.Key,
x => x.Sum(t => Convert.ToDecimal(t.EnergyConsumptionQt)));
and you can access it's elements with something like:
var elem = test[new DictKey{Id=1, UtilityName="myUtiName"}]

How to populate a Class with Dictionary using LINQ

In my project I use an XML to import various instances of a class.
I need to import in a List.
The problem is how to import all "dynamicDrop" in a Dictionary:
XML:
<LootProfile name="volpeNormale">
<dynamicDropNumber>3</dynamicDropNumber>
<dynamicDrop>70</dynamicDrop>
<dynamicDrop>40</dynamicDrop>
<dynamicDrop>10</dynamicDrop>
<dynamicTypeArmor>33</dynamicTypeArmor>
<dynamicTypeWeapon>33</dynamicTypeWeapon>
<dynamicTypeConsumable>34</dynamicTypeConsumable>
<dynamicRarityCommon>70</dynamicRarityCommon>
<dynamicRarityUncommon>20</dynamicRarityUncommon>
<dynamicRarityRare>8</dynamicRarityRare>
<dynamicRarityEpic>2</dynamicRarityEpic>
<staticDropNumber>2</staticDropNumber>
<staticDrop idPattern="100">60</staticDrop>
<staticDrop idPattern="145">100</staticDrop>
<faction>All</faction>
<location>All</location>
</LootProfile>
XMLImporter query:
var query = from item in xml.Root.Elements("LootProfile")
select new LootProfile()
{
name = (string)item.Attribute("name"),
dynamicDropNumber = (int)item.Element("dynamicDropNumber"),
dynamicDrop = (Dictionary<int,string>)item.Element("dynamicDrop) //this one doesnt work!
//other element....
}
return query.ToList<LootProfile>();
Here is how you can do it:
var query = xml.Elements("LootProfile")
.Select(item => new LootProfile()
{
name = (string) item.Attribute("name"),
dynamicDropNumber = (int) item.Element("dynamicDropNumber"),
dynamicDrop =
item.Elements("dynamicDrop")
.Select((Item, Index) => new {Item, Index})
.ToDictionary(x => x.Index, x => float.Parse(x.Item.Value))
//other element....
});
var result = query.ToList();
The trick is to use an overload of Select that gives you two lambda parameters; the item itself, and the index of the item.

GroupBy of Anonymous Object strange result

I am getting an unexpected result from GroupBy in this case, I expect a Dictionary<string,List<object>> from GroupBy. But the browser receives something like: [{playdate, experiencetype...}, { ... }, { }], [{playdate, experiencetype,... }, { } ],...
So there are no Keys even though the objects are grouped into arrays, but I want Keys to be there. I put up a breakpoint and checked packagedAjax, and there seems to be a GroupedEnumerable there containing Lookups. Any thoughts?
var packagedAjax = showtimesByMovieAndLocation
.Select(x =>
new
{
playdate = x.PlayDate,
experiencetype = x.FFCode,
vistasessionid = x.SessionID,
areacode = x.AreaCode
})
.GroupBy(x => x.experiencetype);
return new JsonpResult(packagedAjax, Request.QueryString["callback"]);
GroupBy returns an IGrouping, not a Dictionary. If you want a Dictionary, convert it using .ToDictionary():
var packagedAjax = showtimesByMovieAndLocation
.Select(x =>
new
{
playdate = x.PlayDate,
experiencetype = x.FFCode,
vistasessionid = x.SessionID,
areacode = x.AreaCode
})
.GroupBy(x => x.experiencetype)
.ToDictionary(g => g.Key, g => g.ToList());

Linq two select statements, second one uses first ones result,

This linq query works well.
var qry = context.Boxes
.GroupBy(k=>k.Box_ID)
.Select( group => new {
Box_ID = group.Key,
TotalA = group.Sum(p => p.A),
TotalC = group.Sum(p => p.C)
})
.Select(p => new {
Box_ID = p.Kasa_ID,
TotalA = p.TotalA,
TotalC = p.TotalC,
DiffAC = p.TotalA - p.TotalC
});
But, i saw these type select statements, second one uses first select's anonymous type result, written like this:
var qry = context.Boxes
.GroupBy(k => k.Box_ID)
.Select(group => new
{
Box_ID = group.Key,
TotalA = group.Sum(p => p.A),
TotalC = group.Sum(p => p.C)
})
.Select(p => new
{
Box_ID, //*** compiler error
TotalA, //I'm asking about these 3 lines, is this syntax possible
TotalC, //TotalC = p.TotalC,
DiffAC = p.TotalA - p.TotalC // calculate
});
comments contains details.
When i try to compile second query, compiler gives me the error "The name 'Box_ID' does not exist in the current contex".
In fact there is no doubt with first syntax, but second one is more readable. How can i use second syntax? or in which condititons i can use it.
.Select(p => new
{
p.Box_ID,
p.TotalA,
p.TotalC,
DiffAC = p.TotalA - p.TotalC // calculate
});

Categories