Nested group by based on flatten record set - c#

I have the following responses from the API. How can I group them into the following structure?
Student[]
- Name
- Classes[]
- ClassName
- ClassId
- ClassCategories[]
- CategoryName
- CategoryWeight
- Assignments[]
- AssignmentName
- Score
I was managed to group them until the "Classes" level but unable to get the ClassCategories for each of the classes
var data = (from result in results
group result by new { result.StudentId, result.FirstName, result.LastName, result.MiddleInitial }
into StudentGroup
select new GroupedStudent
{
StudentId = StudentGroup.Key.StudentId,
FullName = string.Format("{0} {1} {2}", StudentGroup.Key.FirstName, StudentGroup.Key.MiddleInitial, StudentGroup.Key.LastName).Replace(" ", " "),
Classes = from result in results
group result by new { result.ClassId, result.ClassName } into ClassGroup
select new groupedClass
{
ClassName = ClassGroup.Key.ClassName,
ClassId = ClassGroup.Key.ClassId,
ClassCategories = ...
})
}).ToList();
Can anyone please assists me? Thank you.

First, you have make ClassGroup from StudentGroup not from results.
Classes = from s in StudentGroup group result by new { s.ClassId, s.ClassName } into ClassGroup
The complete linq query is as follows:
var data =
(from result in results
group result by new { result.StudentId, result.FirstName, result.LastName, result.MiddleInitial } into StudentGroup
select new
{
StudentId = StudentGroup.Key.StudentId,
FullName = string.Format("{0} {1} {2}", StudentGroup.Key.FirstName, StudentGroup.Key.MiddleInitial, StudentGroup.Key.LastName).Replace(" ", " "),
Classes = (from s in StudentGroup
group s by new { s.ClassId, s.ClassName } into ClassGroup
select new
{
ClassId = ClassGroup.Key.ClassId,
ClassName = ClassGroup.Key.ClassName,
ClassCategories = (from c in ClassGroup
group c by new { c.CategoryName, c.CategoryWeight } into CategoryGroup
select new
{
CategoryName = CategoryGroup.Key.CategoryName,
CategoryWeight = CategoryGroup.Key.CategoryWeight,
Assignments = (from ct in CategoryGroup
group ct by new { ct.AssignmentName, ct.Score } into AssingnmentGroup
select new
{
AssignmentName = AssingnmentGroup.Key.AssignmentName,
Score = AssingnmentGroup.Key.Score
}).ToList()
}).ToList()
}).ToList()
}).ToList();
For example, if you want to access to the first Assignment's score, you can get it like this:
var student = data.FirstOrDefault();
var score = student.Classes[0].ClassCategories[0].Assignments[0].Score;

This is usually how I do It.
Create a class to store your data
Create a list of that class type
In your case instead of string dataRow maybe you can use a sub class
.
// get data from webservice
var json = webClient.DownloadString(url);
var values = JsonConvert.DeserializeObject<JArray>(json);
// create a list to save all the element
List<myClass> classList = new List<myClass>();
// process every row
foreach (string dataRow in values)
{
string[] dataField = dataRow.Split(',');
// have a constructor to assign each value to this element
myClass ctROW = new myClass(dataField);
classList.add(ctROW );

Related

How to return list of object which associated with one ID?

I am still getting familiar with SQL and LINQ and I am trying to get every objects and its objects which is under one ID.
The below is the EDMX Diagram.
I am passing ClientID and I want to list everything that is under that ClientID and the below is my query to do so but as you can see query is only returning the first element but how to change it to return the list of every elements as below:
Passed ClientID
THeaderTitle 1
TReportName 1
TReportName 2
MY query is below which is returning the first element:
public TReportHeaderModel GetHeadersByClient(int ClientID)
{
using (var connection = new TReportEntitiesConnection())
{
var query = (from c in connection.THeader.Include("TReports")
where
c.ClientID == ClientID
select new TReportHeaderModel()
{
ID = c.ID,
THeaderTitle = c.THeaderTitle,
RowNumber = c.RowNumber,
TReports = (from t in c.TReports
select new TReportModel()
{
ID = t.ID,
TReportName = t.TReportName,
URL = t.URL,
RowNumber = t.RowNumber
}).ToList()
}).First();
return query;
}
}
I've got it working!
I had to change it in my interface as
IList GetHeadersByClient (int ClientID);
So that I can return List of elements in my controller to pass to view.
public IList<TReportHeaderModel> GetHeadersByClient(int ClientID)
{
using (var connection = new TReportEntitiesConnection())
{
var query = (from c in connection.THeader.Include("TReports")
where
c.ClientID == ClientID
select new TReportHeaderModel()
{
ID = c.ID,
THeaderTitle = c.THeaderTitle,
RowNumber = c.RowNumber,
TReports = (from t in c.TReports
select new TReportModel()
{
ID = t.ID,
TReportName = t.TReportName,
URL = t.URL,
RowNumber = t.RowNumber
}).ToList()
});
return query.ToList();
}
}

In this particular example, how can I get the first record in each group?

In the code below, how can I get the first record in each group? My real query is more complex and I have to create the anonymous types, then use LoadDataRow on the dtResult table that I have created. I need to do this so I can use the CopyToDataTable functionality on my result:
var results =
(from cust in customers
join invoice in invoices
on
new
{
Prefix = cust.Field<string>("Prefix"),
CustNumb = cust.Field<int>("CustomerNumber")),
Suffix = cust.Field<int>("Suffix"))
}
equals
new
{
Prefix = invoice.Field<string>("Prefix"),
CustNumb = invoice.Field<int>("CustomerNumber"),
Suffix = invoice.Field<int>("Suffix")
}
group cust by new
{
Prefix = cust["Prefix"],
CustomerNumber = cust["CustomerNumber"],
Suffix = cust["Suffix"],
Name = cust["Name"],
Address = cust["Address"]
}
into groups
orderby groups.Key.Name
// how do I get only the first record of each group?
select dtResult.LoadDataRow(
new object[]
{
groups.Key.Prefix,
groups.Key.CustomerNumber,
groups.Key.Suffix,
groups.Key.Name,
groups.Key.Address
}, false)
);

Group by single column in Linq c#

I have a table like below: I need to display it as without duplicates. So I need to groupby customer alone. c1 has both 'Name'
Id Name customer
1 XXXX c1
2 YYYY c1
I need to get the values on c1 : xxx ,yyy. But its getting c1: xxx and c1: yyy.
My code is:
public List<data> GetComponentStatus()
{
List<data> d= null;
using(var entity=new FM())
{
d = entity.getdata()
.Select(
a => new data
{
Customer = a.id,
Name = a.name,
})
.GroupBy(a=>a.Customer).Select(a=>a.FirstOrDefault()).ToList();
}
return d;
}
From this, I am getting the first record or last record when using LastorDefault().
I want to get both 'Name' on single Customer C1.
If I understood correctly you want to group by Customer and get Name as comma seperated. I created sample data of yours and wrote LINQ in query syntax. See the demo output on rextester below.
var data = new[] { new {ID = 1,Name = "XXXX", customer= "C1"},
new {ID = 2,Name = "YYYY", customer= "C1"},
};
var query = from a in data
group a by a.customer into grp
select new {Cutomer= grp.Key ,Name = string.Join(",",grp.Select (g => g.Name)) };
foreach (var e in query)
{
Console.WriteLine("Customer: {0} ,Name: {1}", e.Cutomer,e.Name);
}
Its Demo on rextester
So your code should be like this
public List<data> GetComponentStatus()
{
using(var entity=new FM())
{
var d = from a in entity.getdata()
group a by a.customer into grp
select new data {Cutomer= grp.Key ,Name = string.Join(",",grp.Select (g => g.Name))};
return d.ToList();
}
}

List order by another contained list

I have a list of Objects and one of the item is another list. How can I Group them based on the inner list.
Here is an example of what I wish to do.
class Student
{
public string Name;
public int Age;
public List<GroupInfo> GroupList; // This is the inner list
}
class GroupInfo
{
public string GroupName;
public int GroupId;
}
static void Main()
{
GroupInfo firstGroup = new GroupInfo
{
GroupId = 1,
GroupName = "First group"
};
GroupInfo secondGroup = new GroupInfo
{
GroupId = 2,
GroupName = "Second group"
};
GroupInfo thirdGroup = new GroupInfo
{
GroupId = 3,
GroupName = "Third group"
};
GroupInfo fourthGroup = new GroupInfo
{
GroupId = 4,
GroupName = "Fourth group"
};
List<Student> studentList = new List<Student>();
Student firstStudent = new Student();
firstStudent.Name = "Name1";
firstStudent.Age = 15;
firstStudent.GroupList = new List<GroupInfo>();
firstStudent.GroupList.Add(firstGroup);
firstStudent.GroupList.Add(secondGroup);
studentList.Add(firstStudent);
Student secondStudent = new Student();
secondStudent.Name = "Name2";
secondStudent.Age = 17;
secondStudent.GroupList = new List<GroupInfo>();
secondStudent.GroupList.Add(firstGroup);
secondStudent.GroupList.Add(thirdGroup);
studentList.Add(secondStudent);
Student thirdStudent = new Student();
thirdStudent.Name = "Name3";
thirdStudent.Age = 18;
thirdStudent.GroupList = new List<GroupInfo>();
thirdStudent.GroupList.Add(secondGroup);
thirdStudent.GroupList.Add(thirdGroup);
thirdStudent.GroupList.Add(fourthGroup);
studentList.Add(thirdStudent);
List<GroupInfo> groupInfoList = new List<GroupInfo>();
// Now What I want is to get a group List Where...
foreach (var student in studentList)
{
// ...First Group Should contains firstStudent and secondStudent
// Second group Should firstStudent & thirdStudent
// Third group Should contains secondStudent & thirdStuden
// Fourth Group Should contains only thirdStudent
}
}
One way is to iterate on the whole List and populate the GroupInfo List. Just wondering is there any other way to do this task.
You can do this with SelectMany like this:-
var result = studentList.SelectMany(x => x.GroupList,
(studentObj, groups) => new { studentObj, groups })
.GroupBy(x => new { x.groups.GroupId, x.groups.GroupName })
.Select(x => new
{
GroupId = x.Key.GroupId,
GroupName = x.Key.GroupName,
Students = x.Select(z => z.studentObj).ToList()
});
Since your GroupInfo class only has two properties i.e. GroupId & GroupName, you won't be able to fetch the Students associated with it. This is the reason I am fetching anonymous type out of it.
I am getting following output with this query:-

Linq query for group by multiple item

I have a linq query which is working fine.How can i use group by in this query.I need to group by username and itemid and i should get sum(Amount)(All are in table called Carts)
FoodContext db = new FoodContext();
List<CartListing> fd = (from e in db.FoodItems
join o in db.Carts on e.itemid equals o.itemid
where e.itemid == o.itemid
select new CartListing
{
Itemname =e.itemname,
Amount =o.amount,
Price=(float)(e.price*o.amount),
}).ToList();
CartModel vm = new CartModel { CartListings = fd };
I can't see username anywhere in your code example, but to group by Itemname and sum Amount, you would something like:
var grouped = fd.GroupBy(
cl => cl.Itemname,
(key, group) => new CartListing
{
Itemname = key,
Amount = group.Sum(cl => cl.Amount),
Price = group.Sum(cl => cl.Price)
});
To also group by username, just generate a text key containing both values, for instance delimited by a character you know will be contained in neither.
Use:
var grouped = fd.GroupBy((a => new { a.itemid,a.name }) into grp
select new MyClass
{
MyProperty1=grp.key.itemid,
MyProperty2 =grp.Sum(x=>x.whatever)
}
Public MyClass
{
public string MyProperty1 {get;set;}
public int MyProperty2 {get;set;}
}
This way it won't be anonymous

Categories

Resources