GroupBy of Anonymous Object strange result - c#

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());

Related

Trying to convert dictionary results to tuples using same dictionary keys to filter

I have a query that will give the results in the dictionary <Guid, List<Energy>>, and then I filter the dictionary results by using the other dictionary key, which is working fine.
Now I would like to apply this filtering right after dictionary results in a single statement, and the result would be tuples.
Below is the query for where I am getting results in the form of a dictionary
var energiesByBenchmarkingEnergyModelTypeId = BenchmarkingModeledEnergyItems
?.GroupBy(o => o.BenchmarkingEnergyModelTypeId)
.ToDictionary(o => o.Key,
o => o.Select(p => new Energy
{
Unit = energyUnitById[p.Energy.UnitId],
Scalar = p.Energy.Scalar
}).ToList());
and below is where I am filtering the dictionary results with other dictionaries and getting the results
List<Energy> proposedEnergies = null;
List<Energy> baselineEnergies = null;
energiesByBenchmarkingEnergyModelTypeId?.TryGetValue(benchmarkingEnergyModelTypeIdByName["Proposed"], out proposedEnergies);
energiesByBenchmarkingEnergyModelTypeId?.TryGetValue(benchmarkingEnergyModelTypeIdByName["Baseline"], out baselineEnergies);
Now would like to get these from the above query, and the sample output looks like the below.
var (proposedEnergies, baselineEnergies) = BenchmarkingModeledEnergyItems
?.GroupBy(o => o.BenchmarkingEnergyModelTypeId)
......
I am trying to figure out how to convert dictionary results to tuples, but I couldn't figure out how to filter the results with the key.
var (proposedEnergies, baselineEnergies) = BenchmarkingModeledEnergyItems
?.GroupBy(o => o.BenchmarkingEnergyModelTypeId)
.ToDictionary(o => o.Key,
o => o.Select(p => new Energy
{
Unit = energyUnitById[p.Energy.UnitId],
Scalar = p.Energy.Scalar
}).ToList())
.Select(a => new Tuple<List<Energy>, List<Energy>>()); // here need to filter out the results and add to the tuples
Could anyone suggest any ideas on this?
Thanks in advance!!!
Well, the following might meet your needs. See what you think.
var proposedModelType = benchmarkingEnergyModelTypeIdByName["Proposed"];
var baselineModelType = benchmarkingEnergyModelTypeIdByName["Baseline"];
var (proposedEnergies, baselineEnergies) = new Tuple<List<Energy>, List<Energy>>(
// Query BMEI, filtering by "Proposed" ModelTypeId
BenchmarkingModeledEnergyItems
.Where(o => o.BenchmarkingEnergyModelTypeId == proposedModelType)
// Make the new "Energy" items.
.Select(p => new Energy
{
Unit = energyUnitById[p.Energy.UnitId],
Scalar = p.Energy.Scalar
})
.ToList(),
// Query BMEI, filtering by "Baseline" Model Type ID
BenchmarkingModeledEnergyItems
.Where(e => e.BenchmarkingEnergyModelTypeId == baselineModelType)
// Make the new "Energy" items.
.Select(p => new Energy
{
Unit = energyUnitById[p.Energy.UnitId],
Scalar = p.Energy.Scalar
})
.ToList()
);
But your original version is probably the simplest solution!

how to aggregate a linq query by different groupings

How do you perform multiple seperate aggregations on different grouping in linq?
for example, i have a table:
UNO YOS Ranking Score
123456 1 42 17
645123 3 84 20
I want to perform an set of aggregations on this data both grouped and ungrouped, like:
var grouped = table.GroupBy(x => x.score )
.Select(x => new
{
Score = x.Key.ToString(),
OverallAverageRank = x.Average(y => y.Ranking),
Year1RankAvg = x.Where(y => y.YOS == 1).Average(y => y.Ranking),
Year2RankAvg = x.Where(y => y.YOS == 2).Average(y => y.Ranking)
//...etc
});
I also want to perform different aggregations (standard deviation) on the same slices and whole-set data.
I can't figure out how to both group and not group the YOS at the same time and while this compiles fine, when it comes to runtime, I get "Sequence contains no elements", if any of the YOS averages are in.
Like anything programming, when you have a sequence of similar items, use a collection. In this case, I left it IEnumerable, but you could make it a List, or a Dictionary by YOS, if desired.
var ans = table.GroupBy(t => t.Score)
.Select(tg => new {
Score = tg.Key,
OverallAverageRank = tg.Average(t => t.Ranking),
YearRankAvgs = tg.GroupBy(t => t.YOS).Select(tyg => new { YOS = tyg.Key, RankAvg = tyg.Average(t => t.Ranking) })
});
If you need the range of years from 1 to max (or some other number) filled in, you can modify the answer:
var ans2 = ans.Select(soryr => new {
soryr.Score,
soryr.OverallAverageRank,
YearRankDict = soryr.YearRankAvgs.ToDictionary(yr => yr.YOS),
YearMax = soryr.YearRankAvgs.Max(yr => yr.YOS)
})
.Select(soryr => new {
Score = soryr.Score,
OverAverageRank = soryr.OverallAverageRank,
YearRankAvgs = Enumerable.Range(1, soryr.YearMax).Select(yos => soryr.YearRankDict.ContainsKey(yos) ? soryr.YearRankDict[yos] : new { YOS = yos, RankAvg = 0.0 }).ToList()
});
If you preferred, you could modify the original ans to return RankAvg as double? and put null in place of 0.0 when adding missing years.

Improving conversion from List to List<Dictionary<string,string>> with Linq

I've a Key/Value table in my DB and I would return a List of Dictionary.
The following code works fine for me but with a lot of data is not performing.
note: r.name doesn't contains unique value
List<Dictionary<string, string>> listOutput = null;
using (ExampleDB db = new ExampleDB())
{
var result = (from r in db.FormField
where r.Form_id == 1
select new { r.ResponseId, r.name, r.value}).toList();
listOutput = new List<Dictionary<string, string>>();
foreach (var element in result)
{
listOutput.Add((from x in listOutput
where x.ResponseId == element.ResponseId
select x).ToDictionary(x => x.name, x => x.value));
}
}
return listOutput;
Do you have suggestions on how to improve this code ?
I suspect you want something like:
List<Dictionary<string, string>> result;
using (var db = new ExampleDB())
{
result = db.FormField
.Where(r => r.Form_id == 1)
.GroupBy(r => r.ResponseId, r => new { r.name, r.value })
.AsEnumerable()
.Select(g => g.ToDictionary(p => p.name, p => p.value))
.ToList();
}
In other words, we're filtering so that r.Form_id == 1, then grouping by ResponseId... taking all the name/value pairs associated with each ID and creating a dictionary from those name/value pairs.
Note that you're losing the ResponseId in the list of dictionaries - you can't tell which dictionary corresponds to which response ID.
The AsEnumerable part is to make sure that the last Select is performed using LINQ to Objects, rather than trying to convert it into SQL. It's possible that it would work without the AsEnumerable, but it will depend on your provider at the very least.
From what I gather you're trying to create a list of Key/Value pairs based on each ResponseId. Try GroupBy:
var output = result.GroupBy(r => r.ResponseId)
.Select(r => r.ToDictionary(s => s.Name, s => s.Value));
This will return an IEnumerable<Dictionary<string,string>>, which you can ToList if you actually need a list.

The type of the arguments cannot be inferred usage Linq GroupJoin

I'm trying to make a linq GroupJoin, and I receive the fore mentioned error. This is the code
public Dictionary<string, List<QuoteOrderline>> GetOrderlines(List<string> quoteNrs)
{
var quoteHeadersIds = portalDb.nquote_orderheaders
.Where(f => quoteNrs.Contains(f.QuoteOrderNumber))
.Select(f => f.ID).ToList();
List<nquote_orderlines> orderlines = portalDb.nquote_orderlines
.Where(f => quoteHeadersIds.Contains(f.QuoteHeaderID))
.ToList();
var toRet = quoteNrs
.GroupJoin(orderlines, q => q, o => o.QuoteHeaderID, (q => o) => new
{
quoteId = q,
orderlines = o.Select(g => new QuoteOrderline()
{
Description = g.Description,
ExtPrice = g.UnitPrice * g.Qty,
IsInOrder = g.IsInOrder,
PartNumber = g.PartNo,
Price = g.UnitPrice,
ProgramId = g.ProgramId,
Quantity = (int)g.Qty,
SKU = g.SKU
}).ToList()
});
}
I suspect this is the immediate problem:
(q => o) => new { ... }
I suspect you meant:
(q, o) => new { ... }
In other words, "here's a function taking a query and an order, and returning an anonymous type". The first syntax simply doesn't make sense - even thinking about higher ordered functions, you'd normally have q => o => ... rather than (q => o) => ....
Now that won't be enough on its own... because GroupJoin doesn't return a dictionary. (Indeed, you don't even have a return statement yet.) You'll need a ToDictionary call after that. Alternatively, it may well be more appropriate to return an ILookup<string, QuoteOrderLine> via ToLookup.

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