I have a list of a class with several properties, I want to group by 5 of them and then order the results of the grouping by 5 different properties. The result should be a List().
Lets say (pseudocode-ish)....
public class cls()
string firstSTR {get;set;}
string secondSTR {get;set;}
string thirdSTR {get;set;}
string fourthSTR {get;set;}
string fifthSTR {get;set;}
List<cls> vals = new List<cls>();
var tmp = PopulateList(); // Here I would populate several hundred cls()
var unique = tmp.GroupBy(i => new {
i.firstSTR,
i.secondSTR,
i.thirdSTR,
i.fourthSTR,
i.fifthSTR
}).ToList().OrderBy (i => new {
i.firstSTR,
i.secondSTR,
i.thirdSTR,
i.fourthSTR).ToList();
I have very limited experience with Linq and I am not able to figure out why this does not work. The result of the first group by does not return a list of cls so I am not even sure how I can define what I want to order on. I hope that I have provided enough information to explain what I am trying to do. Thank you in advance.
----- EDIT -------
Here is what some example data might look like. I have included 10 columns of sample data however the there are more like 50 columns in the class.
Last5|First5|Add5|ZipCode|InsuranceName|Policy#|Group#|GroupName|SubscriberName|SubscriberAddress
SMITH|JOHN|123 M|99523|Medicare|POL123|GRP123|GRPNM|SMITH| JOHN|123 MAIN ST 99253
SMITH|JOHN|123 M|99523|Medicare|POL123|GRP123|GRPNM|SMITH| JOHN|123 MAIN ST 99253
SMITH|JOHN|123 M|99523|Commercial|POL456|GRP456|GRRNM|SMITH| JOHN|123 MAIN ST 99253
SMITH|MARY|992 W|99324|Medicare|POL789|GRP789|GRPNM|SMITH|MARY|992 WEST ST 99324
SMITH|MARY|992 W|99324|Commerical|POLXXY|GRPXXY|GRPNM|SMITH|MARY|992 WEST ST 99324
Above there are 5 records, delimited with pipe. The output data must be unique on the first 5 fields: Last5, First5, Add5, ZipCode, and Insurance name. Although I am looking to group on these first 5 columns I need all the data in the original class object populated in the result. My result data should look like this.
Last5|First5|Add5|ZipCode|InsuranceName|Policy#|Group#|GroupName|SubscriberName|SubscriberAddress
SMITH|JOHN|123 M|99523|Medicare|POL123|GRP123|GRPNM|SMITH| JOHN|123 MAIN ST 99253
SMITH|JOHN|123 M|99523|Commercial|POL456|GRP456|GRRNM|SMITH| JOHN|123 MAIN ST 99253
SMITH |MARY|992 W|99324|Medicare|POL789|GRP789|GRPNM|SMITH|MARY|992 WEST ST 99324
SMITH |MARY|992 W|99324|Commerical|POLXXY|GRPXXY|GRPNM|SMITH|MARY|992 WEST ST 99324
The result should only have 4 records as one Medicare Records for John Smith has been removed because the first 5 fields are a duplicate of another. Any other field in the remaining 5 columns (again, 50 or so in my data) can be the same, or different, it does not matter.
Im assuming that you don't want aggregates
var unique = tmp.GroupBy(i => new {
i.firstSTR,
i.secondSTR,
i.thirdSTR,
i.fourthSTR,
i.fifthSTR
}).Select(p=> new {
firstSTR = p.Key.firstSTR,
secondSTR = p.Key.secondSTR,
thirdSTR = p.Key.thirdSTR,
fourthSTR= p.Key.fourthSTR,
fifthSTR =p.Key.fifthSTR,
}).OrderBy(p=> p.firstSTR)
.ThenBy(p=> p.secondSTR)
.ThenBy(p=> p.thirdSTR)
.ThenBy(p=> p.fourthSTR)
.ThenBy(p=> p.fifthSTR)
.ToList();
Related
I guess there must be an easy way, but not finding it. I would like to check whether a list of items, appear (completely or partially) in another list.
For example: Let's say I have people in a department as List 1. Then I have a list of sports with a list of participants in that sport.
Now I want to count, in how many sports does all the people of a department appear.
(I know some tables might not make sense when looking at it from a normalisation angle, but it is easier this way than to try and explain my real tables)
So I have something like this:
var peopleInDepartment = from d in Department_Members
group d by r.DepartmentID into g
select new
{
DepartmentID = g.Key,
TeamMembers = g.Select(r => d.PersonID).ToList()
};
var peopleInTeam = from s in Sports
select new
{
SportID = s.SportID,
PeopleInSport = s.Participants.Select(x => x.PersonID),
NoOfMatches = peopleInDepartment.Contains(s.Participants.Select(x => x.PersonID)).Count()
};
The error here is that peopleInDepartment does not contain a definition for 'Contains'. Think I'm just in need of a new angle to look at this.
As the end result I would like print:
Department 1 : The Department participates in 3 sports
Department 2 : The Department participates in 0 sports
etc.
Judging from the expected result, you should base the query on Department table like the first query. Maybe just include the sports count in the first query like so :
var peopleInDepartment =
from d in Department_Members
group d by r.DepartmentID into g
select new
{
DepartmentID = g.Key,
TeamMembers = g.Select(r => d.PersonID).ToList(),
NumberOfSports = Sports.Count(s => s.Participants
.Any(p => g.Select(r => r.PersonID)
.Contains(p.PersonID)
)
)
};
NumberOfSports should contains count of sports, where any of its participant is listed as member of current department (g.Select(r => r.PersonID).Contains(p.PersonID))).
I am new to LINQ. I am stuck with a very silly problem
Name Subjects Role
---- -------- --------
A Math Student
A English Student
B Math Student
B English Student
C Math Student
C Math Admin
I need result as
Name Subjects Role
---- -------- --------
A Math, English Student
B Math, English Student
C Math Student
C Math Admin
I am confused as to how to go about this problem. This is simple in SQL where I can do a groupby clause and get the comma seperated values via a function.
Can someone please help me out?
Edited: The three columns are from 3 different sources. I have updated the resultant table. Thanks for your help in advance!
I don't have your code but it should look like this:
var grouped = from element in yourList
group element by element.Name into g
select new
{
Name = g.Key,
Subjects = g.Select(e => e.Subject),
// Assuming they are identical when they have the same name
Role = g.First().Role
};
Try this:
var grouped = classes.GroupBy(g => new {Name = g.Name, Role = g.Role}).Select(
s =>
new
{
Name = s.Key,
Subjects = s.Select(x => x.Subject).Aggregate("", (current, se) => current + (", " + se)),
Role = s.Select(x => x.Role).First()
});
var result = grouped.Select(s => new
{
s.Name,
Subjects = s.Subjects.Substring(2),
s.Role
}).ToList();
This will put your subjects in a comma separated string.
Hope this helps.
I am currently using SharePoint 2010,and in my business layer I am using LINQ to SharePoint. I generated all my Entity classes using SPMetal.
We are creating a Library system, my system has 2 Lists . The first one is Contribution and the second one is Contributor. Each Contributor contains a reference to the Contribution List (a PrimaryISBN reference). The Contribution List contains list of books and PrimaryISBN is not unique in this list.
Contribution
ID PrimaryISBN TITLE
1 PRIM1 HardcoverLOTR
2 PRIM1 AudioBookLOTR
3 PRIM2 HardcoverHP
Contributor
ID Name PrimaryISBNLookup
1 ABC PRIM1
2 DEF PRIM2
I am currently trying to fetch All the Books Contributed by a Particular user based on the Name.
My query is something like this
var result = from _contributor in data.contributor
where _contributor.Name= "ABC"
select new Book
{
Title = contributor.PrimaryISBNLookup.Title
}
The problem that I am currently facing is in retrieving records that have same ISBN but different title (Each format will have a title i.e. a Audio book will have a title and a Hardcover of the same book will have a different one).
This query returns me only 1 records even thought I have 2 records in my system i.e. the record with ID (in Contribution) that I am forced to insert during the insertion of record into Contributor List.
Your help is highly appreciated.
From what I understand, you try to implement a simple join, like this:
var results = from _contributor in data.contributor
join _contribution in data.contribution
on _contributor.PrimaryISBNLookup equals _contribution.PrimaryISBN
where _contributor.Name == "ABC"
select new Book
{
Title = _contribution.Title
}
If you want to use DataTable in SPList, try this:
SPList cList = spWeb.Lists.TryGetList("Customer");
SPList oList = spWeb.Lists.TryGetList("Order");
DataTable cTable= cList.Items.GetDataTable();
DataTable oTable= oList.Items.GetDataTable();
var coList = from tbl1 in cTable.AsEnumerable()
join tbl2 in oTable.AsEnumerable() on tbl1["Title"] equals tbl2["CustomerName"]
select new
{
ItemName = tbl2["Title"],
CustomerName = tbl1["Title"],
Mobile = tbl1["MobileNo"]
};
var customer= from cust in customerData
select new Customer
{
CustomerID = cust["id"],
Name = cust["Name"],
LastVisit = cust["visit"],
PurchashedAmount = cust["amount"],
Tagged = cust["tagged"]
Code = cust["code"]
}
The rows looks like this
Name LastVisit PurchasedAmount Tagged Code CustomerID
------ --------- -------------- ------ ----- -----
Joshua 07-Jan-09 Yes chiJan01 A001
Joshua 10000
The 2nd row belongs to first row just that the other columns are empty.How can i merge the PurchasedAmount into the first row using LinQ?
This is probably a more general solution than you need - it will work even if the other values are scattered across rows. The main condition is that the Name column should identify rows that belong together.
customer = from c in customer
group c by c.Name
into g
select new Customer
{
Name = g.Key,
LastVisit = g.Select(te => te.LastVisit).
Where(lv => lv.HasValue).FirstOrDefault(),
PurchaseAmount = g.Select(te => te.PurchaseAmount).
Where(pa => pa.HasValue).FirstOrDefault(),
Tagged = g.Select(te => te.Tagged).
Where(ta => ta.HasValue).FirstOrDefault(),
Code = g.Select(te => te.Code).
Where(co => !string.IsNullOrEmpty(co)).FirstOrDefault(),
CustomerID = g.Select(te => te.CustomerID).
Where(cid => !string.IsNullOrEmpty(cid)).FirstOrDefault()
};
This will return a new IEnumerable with the items grouped by Name and the non-null values selected (same effect as moving PurchasedAmount to the first row and deleting the second in your case).
Note that the code is based on the assumption that LastVisit, PurchaseAmount and Tagged are nullable types (DateTime?, int? and bool?). Thus the usage of HasValue. If, however, they are strings in your case, you have to use !string.IsNullOrEmpty() instead (as for Code and CustomerID).
I have a single table and I need to build a bunch of nested objects based on the single table.
Data:
PointA PointB Month Time Price
1 2 11 11:00 10.99
1 2 12 11:00 9.99
Objects are
POINTS {PointA, PointB, Details}
Details {Month, ExtraDetails}
ExtraDetails {Time, Price}
I want to avoid having loads of loops and if statements, so should be able to use linq to do this. but its beyond my linq experience.
edit: These need grouping aswell
any help would be great.
Thanks
Just tried out a solution:
var nestedObjects = from row in data
select new {row.PointA, row.PointB, Details = new {
row.Month, ExtraDetails = new {
row.Time, row.Price
}
}};
This is assuming that you have already got your data into data.
Group by
If you want to group the Points together, you need 'Group By':
var nestedObjects = from row in data
group row by new { row.PointA, row.PointB } into Points
select new {
Points = Points.Key,
Details = from details in Points
select new { row.Month, ExtraDetails = new {
row.Time, row.Price
}}
};
A little more complicated - of course you might want to group by month as well, in which case, you need to follow the same pattern as for the Points bit. Note, this will not create tables, because the group by doesn't quite do that, but it at least creates the structure for you.
Assuming you got your classes defined for the objects you mentioned, and you have a constructor or properties so you can propery create the object in one line you could have a LINQ query returning a list of a POINTS.
If would go something lik this :
var res =
from item in table.AsEnumerable()
select new Points(){PointA = item["PointA"];
PointB = item["PointB"];
Details = from item2 in table.AsEnumberable()
where item["PointA"] = item2["PointA"] and item["PointB"] = item2["PointB"]
select new Details(){
month=item2["month"],
extraDetails = from item3 in table.AsEnumerable()...
}
};
At the end res will be a IEnumerable of Points
I am sorry for the code, I am not at a computer with .NET 3.5 so I cannot write a proper testable query