Given the following code:
var people = new List<person>(){ new person { Name = "John", FamilyName = "Pendray" },
new person { FamilyName = "Emery", Name = "Jake"},
new person { FamilyName = "Pendray", Name = "Richard" } };
var q = from p in people
orderby p.Name
group p by p.FamilyName into fam
orderby fam.Key
select new { fam.Key, members = from p in fam select p };
Is it possible to replace the last line with a select that will output a IEnumerable<string> that contains these two strings:
"Pendray John Richard"
"Emery Jake"? Is it possible to project a linq query into strings like this?
Edit: I know this is possible with further code but I'm interested in whether this can be done from within the linq query itself in a similar way to VB being able to project xml out of a query as in http://www.thinqlinq.com/default/Projecting-XML-from-LINQ-to-SQL.aspx (particularly the last code block on this page)
var q = from p in people
orderby p.Name
group p by p.FamilyName into fam
orderby fam.Key
select fam.Key + " " + string.Join(" ", (from fm in fam select fm.Name).ToArray());
Returns
Emery Jake
Pendray John Richard
Definitely.
You would have to change the select part. The easiest way would be to define a function that would take the IEnumerable and generate that string, then call that function
people = new List<person>(){ new person { Name = "John", FamilyName = "Pendray" },
new person { FamilyName = "Emery", Name = "Jake"},
new person { FamilyName = "Pendray", Name = "Richard" } };
var q = from p in people
orderby p.Name
group p by p.FamilyName into fam
orderby fam.Key
select new { Key = fam.Key, Text = GetText(fam) };
// and elsewhere...
private string GetText(IEnumerable<person> family) {
string result = "Whatever"; // build the result string here
return result;
}
Also, if you only want the text, you can change the last line of the query to simply
select GetText(fam);
Related
public class Person
{
public string firstName;
public string lastName;
}
I want a list of all Persons with a unique first name.
Persons table
Tom Haverford
Tom Baker
Amy Pond
Amy Santiago
Trish Walker
Chidi Anagonye
The query should return
Trish, Chidi
I've tried using Distinct and a combination of GroupBy and Select, but those return Trish, Chidi, Tom, Amy.
Demo on dotnet fiddle
You can Group by then count number of duplicated items. After that, you can get the item with count value equals to 1 like below.
var arr = new []
{
new Person { firstName = "Tom", lastName = "Haverford" },
new Person { firstName = "Tom", lastName = "Baker"},
new Person { firstName = "Amy", lastName = "Pond" },
new Person { firstName = "Amy", lastName = "Santiago"},
new Person { firstName = "Trish", lastName = "Walker"},
new Person { firstName = "Chidi", lastName ="Anagonye" }
};
var result = arr.GroupBy(p => p.firstName).Select(g => new { Name = g.Key, Count = g.Count()});
foreach(var item in result.Where(p => p.Count == 1))
Console.WriteLine(item.Name);
Output
Trish
Chidi
You can use group by and count functionality together for this :
1. Get a list of all persons from DB :
var personList = (from p in db.Person select p).ToList(); // I assumed here that your db obj name is 'db' and table name is 'Person'
2. Now apply group by query to get the count of first names :
var q = from x in personList
group x by x.firstName into g
let count = g.Count()
select new {Count = count, Name = g.First().firstName };
3. Now you can get your final result like this :
var finalResult = (from p in q where p.Count == 1 select p).ToList();
Happy Coding...
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)
);
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 );
The below code is throwing a "Cannot Enumerate More Than Once" on the second ToList(). What is the best approach for fixing this error?
var firstQuery = (from r in db.SomeProcedure(Id)
select new MyClass
{
Id = r.Id,
Name = r.Name,
Company= r.Company,
Title = r.Title
});
var secondQuery = (from d in firstQuery
group d by d.Title into groupedTitles
select new MyClass2
{
Title = groupedTitles.Key, //How To include the Id
});
List<MyClass> mClass = firstQuery.ToList();
Th Below ToList() is throwing a cannot enumerate more than one
List<MyClass2> mClass2 = secondQuery.ToList();
How can I fix the error?
Convert your first query to a list right away.
var firstQuery = (from r in db.SomeProcedure(Id)
select new MyClass
{
Id = r.Id,
Name = r.Name,
Company= r.Company,
Title = r.Title
}).ToList();
var secondQuery = (from d in firstQuery
group d by d.Title into groupedTitles
select new MyClass2
{
Title = groupedTitles.Key, //How To include the Id
});
List<MyClass> mClass = firstQuery;
List<MyClass2> mClass2 = secondQuery.ToList();
Consider this XML:
I store this XML in XElemnt.How I can loop throw Person elements and get value ID,Name,LastName for each person?
var doc = XDocument.Load(<filePath>);
var people = from person in doc.Descendents("Person")
select new Person{
ID = (int)person.Element("ID"),
Name = (string)person.Element("Name"),
LastName = (string)person.Element("LastName");
};
return people.ToList();
using XElement, you will get all the people in people variable.
XElement d = XElement.Load("D:\\people.xml");
var people = (from p in d.Descendants("Person")
select new
{
ID = Convert.ToInt32(p.Element("ID").Value),
Name = p.Element("Name").Value,
LastName = p.Element("LastName").Value
}).ToList();