How to do 3 nested group by in linq - linq

I found this example of nested group by in linq. How would it look if I want to add one more group by to it?
var queryNestedGroups =
from student in students
group student by student.Year into newGroup1
from newGroup2 in
(from student in newGroup1
group student by student.LastName)
group newGroup2 by newGroup1.Key;

First, let rename some variables of the sample query:
var queryNestedGroups =
from e in source
group e by e.Key1 into g1
from e1 in
(from e in g1
group e by e.Key2)
group e1 by g1.Key;
Now you can add another nested group level using the same pattern:
var queryNestedGroups =
from e in source
group e by e.Key1 into g1
from e1 in
(from e in g1
group e by e.Key2 into g2
from e2 in
(from e in g2
group e by e.Key3)
group e2 by g2.Key)
group e1 by g1.Key;

Related

Can I use a GraphQL union for plain strings?

In Graphql, I can create a union such as the following:
union SearchResult = Book | Movie
Is there a way I can do this for plain strings? Something like this:
union AccountRole = "admin" | "consumer"
I am afraid you cannot do that because it is what defined by the specification.
From the union syntax mentioned at specification here , the part that you want to change should follow the Names syntax , which the first character is only allow to be upper case letter, lower case latter or _
(i.e. the characters set as follows)
A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m
n o p q r s t u v w x y z _

Can you cube between multiple relations in PIG?

I want to find the combination given another variable:
Example:
name, group, points
jim, T, 12
steven, T, 10
ting, T, 15
matt, F, 16
aamir, F, 12
I want to be able to get all combinations between members of T and F and do some multiplication to the points column for that. I first thought to break this into two relations, i.e. a T and an F relation and do some combination between them using CUBE but i don't think you can use CUBE between relations? Any suggestions?
Results:
jim, matt, 12*16
jim, aamir, 12*12
steven, matt, 16*16
...
...
ting, aamir, 15*12
Can you try this?
input.txt
jim,T,12
steven,T,10
ting,T,15
matt,F,16
aamir,F,12
PigScript:
A = LOAD 'input.txt' USING PigStorage(',') AS (name:chararray, group:chararray, points:int);
B = FILTER A BY group=='T';
C = FILTER A BY group=='F';
D = CROSS B,C;
E = FOREACH D GENERATE B::name,C::name,B::points*C::points;
DUMP E;
Output:
(jim,matt,192)
(jim,aamir,144)
(steven,matt,160)
(steven,aamir,120)
(ting,matt,240)
(ting,aamir,180)

How to use a relation to filter a GROUP?

Let's say I have relation A
DUMP A;
(a)
(d)
(g)
And now I want to use A's values to filter a group G:
DUMP G;
(a, {(a,b), (a,c)})
(c, {(c,d), (c,x)})
(d, {(d,b), (d,e)})
...So that the result would be
(a, {(a,b), (a,c)})
(d, {(d,b), (d,e)})
And then I want to extract the groups to generate:
(a,b)
(a,c)
(d,b)
(d,e)
I tried the following to the filtering part, but it didn't work:
J = JOIN G BY group, A BY a1;
R = FOREACH (FILTER J BY J::group == A::a1)
GENERATE FLATTEN(J.group);
If I'm understanding your question correctly, the output of J should already be what you want. By default JOIN is an inner join, so since c does not appear in A it will not be included in the output of J. If you dump J you should see:
(a, {(a,b), (a,c)}, a)
(d, {(d,b), (d,e)}, d)
(Or something similar with the location of the variables switched.)
To FLATTEN out the bag you'll need to do something like:
R = FOREACH J GENERATE FLATTEN(G::FOO) ;
In this case FOO is the name of the relation you did the GROUP on. You can verify its name with DESCRIBE G ;.

linq join with case condition

Hi may i know how to do a select "case" condition in using linq?
The commented out code are my question. how do i put the condition there?
my code:
var r = from u in Users
join p in Payments on u.Id equals p.UserId
join soi in SaleOrderItems on p.ReferenceId equals soi.Id
//if soi.InventoryTypeId == 1
//then join i in Inventories on soi.InventoryOrCourseId equals i.Id
//elseif soi.InventorytypeId ==2
//then join c in Courses on soi.InventoryOrCourseId equals c.Id
where u.Id == 5
select new{ u, p, soi, either i or c};
You have to use some outer join trick to accomplish this, one straightforward method is via DefaultIfEmpty(). Essentially you create an inner join then expand it with missing rows:
var r = from u in Users
join p in Payments on u.Id equals p.UserId
join soi in SaleOrderItems on p.ReferenceId equals soi.Id
join i in Inventories on new {a = soi.InventoryTypeId, b = soi.InventoryOrCourseId } equals new {a = 1, b = i.Id} into g1
from oi in g1.DefaultIfEmpty()
join c in Courses on new {a = soi.InventoryTypeId, b = soi.InventoryOrCourseId } equals new {a = 2, b = c.Id} into g2
from oc in g2.DefaultIfEmpty()
where u.Id == 5
select new{ u, p, soi, ic = oi ?? oc};
Be careful about this last statement ic = oi ?? oc, since the types differ the anonymous type will use System.Object declaration so it can accommodate both types, if you want to use strong typed support maybe a better option would be to return both oc and ic and then test. You should best decide that based on how you use this query late ron.

Converting IGrouping<T,U> to IGrouping<T,V> using LINQ

How can I do this conversion? Is it possible with some simple LINQ query?
If V is some other type not involved in the query, you can use the let keyword to create an instance and then group on it...
from x in Y
let v = new V(x.Whatever)
group v by v.Whatever into vGroup
select vGroup
Assuming that V inherits from U and you want to cast each U to a V :
IEnumerable<IGrouping<string, U>> groupingsOfU =
from u in listOfU
group u by u.Foo;
IEnumerable<IGrouping<string, V>> groupingsOfV =
from g in groupingsOfU
from u in g
group (V)u by g.Key;

Resources