Linq multi column grouping and averaging - linq

I'm trying to get the average of some numbers after grouping but it just won't group for me. Why isn't this doing what I think it should?
var eventInfo = from eventData in dt.AsEnumerable()
group eventData by new
{
Phase1Minutes = eventData.Field<decimal>("Phase1Minutes"),
Phase2Minutes = eventData.Field<decimal>("Phase2Minutes"),
TechnologyType = eventData.Field<string>("TechnologyType"),
TechnologySubType = eventData.Field<string>("TechnologySubType")
} into g
select new
{
Phase1Avg = g.Average(x => x.Field<decimal>("Phase1Minutes")),
Phase2Avg = g.Average(x => x.Field<decimal>("Phase2Minutes")),
g.Key.TechnologyType,
g.Key.TechnologySubType
};

It makes no sense to average over what you're already grouping by. Just to give a trivial example, imagine grouping people by age, and then finding the average age within each group... they're all the same age!
My guess is you just need to take out the minutes parts of the grouping:
var eventInfo = from eventData in dt.AsEnumerable()
group eventData by new
{
TechnologyType = eventData.Field<string>("TechnologyType"),
TechnologySubType = eventData.Field<string>("TechnologySubType")
} into g
select new
{
Phase1Avg = g.Average(x => x.Field<decimal>("Phase1Minutes")),
Phase2Avg = g.Average(x => x.Field<decimal>("Phase2Minutes")),
g.Key.TechnologyType,
g.Key.TechnologySubType
};

Related

linq query crossjoin groupby optimize

i have the following database-model: http://i.stack.imgur.com/gRtMD.png
the many to many relations for Kunde_Geraet/Kunde_Anwendung are in explicit Mapping-Table with additional Information.
i want to optimize the following LINQ-query:
var qkga = (from es in db.Eintrag_Systeme.Where(es => es.Eintrag_ID == id)
from kg in db.Kunde_Geraet.Where(kg => es.Geraet_ID == kg.Geraet_ID)
select new { Kunde = kg.Kunde, Geraet = es.Geraet, Anwendung = es.Anwendung })
.Union(
from es in db.Eintrag_Systeme.Where(es => es.Eintrag_ID == id)
from ka in db.Kunde_Anwendung.Where(ka => es.Anwendung_ID == ka.Anwendung_ID)
select new { Kunde = ka.Kunde, Geraet = es.Geraet, Anwendung = es.Anwendung })
.GroupBy(kga => kga.Kunde, kga => new {Geraet = kga.Geraet, Anwendung = kga.Anwendung});
it would be better, when the result is a IEnumerable(Kunde, IEnumerable(Geraet), IEnumerable(Anwendung)) without the null-Values for the union.
i try it as SQL command
select Count(es.Geraet_ID), null as Anwendung_ID
from Eintrag_Systeme es cross join Kunde_Geraet where es.Geraet_ID = Kunde_Geraet.Geraet_ID AND es.Eintrag_ID = #id
union
select null as Geraet_ID, Count(es.Anwendung_ID)
from Eintrag_Systeme es cross join Kunde_Anwendung where es.Anwendung_ID = Kunde_Anwendung.Anwendung_ID AND es.Eintrag_ID = #id
group by Kunde_ID
but donĀ“t get the Count() of Anwendungen(Apps)/Geraete(Devices) to Lists grouped by Key Kunde(Client)
Don't use join but navigation properties:
from k in context.Kunden
select new
{
Kunde = k,
Geraete = k.Kunde_Geraete.Select(kg => kg.Geraet),
Anwendungen = k.Kunde_Anwendungen.Select(ka => ka.Anwendung)
}
Now you have a basis from which you get counts, etc.

What's the equivalent of GROUP INTO in Linq extension method?

This is how I'm filtering and grouping transTasks.
var transTasks = from t in taskData
where t.RangeName == rName
group t by t.CultureID into g
select new { language = g.Key, tasks = g };
Now I've a new requirement. Depending on the conditions, I'may filter by RangeName or by TaskOrderId.
That's why I've transformed the above Linq code to the following;
var transTasks = taskData
.Where(predicate)
.GroupBy(???)
.Select(???);
I've researched but I can't still find the equivalent of group into for the extension method. I need to group those transTasks because there is a loop inside another loop.
Thanks for helping
GroupBy is the equivalent , and it seems you have figured it out, your query in Method Syntax would be:
var transTrasks = taskData.Where(t => t.RangeName == rName)
.GroupBy(t => t.CultureID)
.Select(g => new { language = g.Key, tasks = g });
As a side note, Any LINQ query in query expression compiles to Method Syntax.
var transTasks = taskData
.Where(predicate)
.GroupBy(t => t.CultureID)
.Select(g => new { language = g.Key, tasks = g });

How to rewrite it more efficiently (linq with split)?

here is the problem:
I have a column with the topics in the format: "boston | new york | chicago". The names can be different and number of the topics can vary in the records.
What I need to come up with is the collection of the same names with the count of those names.
This is what I have done:
var splitted = queryResult.Select(x => x.TopicData);
List<string> lstOfTopics = new List<string>();
foreach (var element in splitted)
{
string[] splitedTopics = element.Split('|');
lstOfTopics.AddRange(splitedTopics);
}
var groupedTopics = lstOfTopics.GroupBy(x => x).Select(group => new {key = group.Key, count = group.Count()}).AsEnumerable();
seems a lot of code for a simple task. any ideas how to simplify this?
thanks!
You can construct the list using SelectMany and ToList:
List<string> lstOfTopics = splitted.SelectMany(x => x.Split('|')).ToList();
You can also omit the construction of the list entirely:
var groupedTopics = queryResult
.SelectMany(x => x.TopicData.Split('|'))
.GroupBy(x => x)
.Select(group => new { group.Key, Count = group.Count()});
var groups = queryResult
.SelectMany(t => t.TopicData.Split('|')
.GroupBy(n => n)
.Select(g => new { Key = g.Key, Count = g.Count() });
query syntax can be nice and compact:
var topics =
from qr in queryResult
from topic in qr.TopicData.Split('|')
group topic by topic into g
select new { Topic = g.Key, Count = g.Count() };
If you want just the unique topics, but not their counts...
List<string> topicList = topics.Select(item => item.Topic);

group by base on 2 element

equal this
select id,name, count(*) from table group by id, name
what is in linq???
In case of entity framework it is better to return computed projection directly from SQL:
var query = from x in context.YourEntities
group x by new { x.ID, x.Name } into y
select new
{
y.Key.ID,
y.Key.Name,
y.Count()
};
This will do Count in database and reduce amount of transferred data.
var groups = table.GroupBy(elt => new {ID = elt.ID, Name = elt.name});
foreach (var group in groups)
{
var ID = group.Key.ID;
var name = group.Key.Name;
var count = group.Count();
...
}

Simple LINQ query

I have a List of X items. I want to have LINQ query that will convert it into batches (a List of Lists), where each batch has 4 items, except for the last one which can have 1-4 (whatever the remainder is). Also, the number 4 should be configurable so it could 5, 17, etc.
Can anyone tell me how to write that?
List<Item> myItems = ...;
List<List<Item>> myBatches = myItems.????
Thank you in advance!
If you're happy with the results being typed as IEnumerable<IEnumerable<T>> then you can do this:
int groupSize = 4;
var myBatches = myItems.Select((x, i) => new { Val = x, Idx = i })
.GroupBy(x => x.Idx / groupSize,
x => x.Val);
If you want an actual List<List<T>> then you'll need to add a couple of extra ToList calls:
int groupSize = 4;
var myBatches = myItems.Select((x, i) => new { Val = x, Idx = i })
.GroupBy(x => x.Idx / groupSize,
x => x.Val,
(k, g) => g.ToList())
.ToList();
Here is a good article about using Take and Skip to do paging, which is identical functionality to what you are requesting. It doesn't get you all of the way to a single line of LINQ, but hopefully helps.
This made me think of how we did this before LINQ.
var vessels = new List<Vessel>()
{ new Vessel() { id = 8, name = "Millennium Falcon" },
new Vessel() { id = 4, name = "Ebon Hawk" },
new Vessel() { id = 34, name = "Virago"},
new Vessel() { id = 12, name = "Naboo royal starship"},
new Vessel() { id = 17, name = "Radiant VII"},
new Vessel() { id = 7, name = "Lambda-class shuttle"},
new Vessel() { id = 23, name = "Rogue Shadow"}};
var chunksize=2;
// With LINQ
var vesselGroups = vessels.Select((v, i) => new { Vessel = v, Index = i })
.GroupBy(c => c.Index / chunksize, c => c.Vessel, (t,e)=>e.ToList())
.ToList();
// Before LINQ (most probably not optimal)
var groupedVessels = new List<List<Vessel>>();
var g = new List<Vessel>();
var chunk = chunksize;
foreach(var vessel in vessels)
{
g.Add(vessel);
chunk--;
if (chunk == 0)
{
groupedVessels.Add(g);
g = new List<Vessel>();
chunk = chunksize;
}
}
groupedVessels.Add(g);

Resources