Group by an array inside an array using Linq - linq

I can use the below code to group by a ID property in an array which works.
var docArray = MyArray;
var docGroup = docArray.GroupBy(x => x.ID)
.Select(grp => new
{
Id = grp.Key,
Results = grp.ToList(),
}).ToList();
If MyArray has another array inside it which has a property say Data can some please tell me how to do the grouping based on the Data property.
class MyArray
{
SecondArray[] arr = new SecondArray[2];
public int ID{get;set;}
}
class SecondArray
{
public string Data{ get; set; }
}

var query = from a in docArray
from b in a.arr
group new { a, b } by b.Data into g
select new
{
g.Key,
Results = g.ToList()
};

Related

How to write a Linq that can retrieve all parent table records and total of sub-table record, I mean 'separate' into two parts

Let's say I have two tables, parent table 'P' and sub-table 'S', I usually wrote the Linq like this to get what I want:
var rows = from p in db.P
join s in db.S on p.Id equals s.ParentId into subContent
where (some condition here)
select new{
Id = p.Id,
Title = p.Title
SubContentCount = subContent.Count()
}
It's very simple, but if for some reason I have to pass a parameter into this query when there has one (let's say 'key'), I have to do this (I guess :-):
var rows = from p in db.P
join s in db.S on p.Id equals s.ParentId into subContent
where (some condition here)
select p;
if(!string.IsNullOrEmpty(key)){ // I'm using C#
rows = rows.Where(q => q.Title.Contains(key))
}
And then:
var list = rows.Select(q => new ()
{
Id = q.Id,
Title = q.Title,
subCount = ???.Count()
});
Is that passable to do Linq like this? if so, how?
Thanks for any kind help!
You could create a method that receives a Func<Table, bool>as parameter and use it to filter your dataset:
public static void Main(string[] args)
{
var rows = new List<Table>
{
new Table { Id = 1, Title = "A", SubContent = new [] { "A1" } },
new Table { Id = 2, Title = "B", SubContent = new [] { "B1", "B2" } },
new Table { Id = 3, Title = "C", SubContent = new [] { "C1", "C2", "C3" } },
};
var title = "C";
foreach (var item in Filter(rows, table =>
String.IsNullOrEmpty(title) || table.Title == title))
{
Console.WriteLine(
"Title={0}, SubContent.Length={1}",
item.Title, item.SubContent.Length);
}
}
public static List<Table> Filter(List<Table> original, Func<Table, bool> filter)
{
return original.Where(filter).ToList();
}
public class Table
{
public int Id { get; set; }
public string Title { get; set; }
public string[] SubContent { get; set; }
}
Why not include the filter in the where clause?
where string.IsNullOrEmpty(key) || p.Title.Contains(key)
Quick example in the interactive console:
public class Parent { public int Id {get; set;} public string Title {get; set;} }
public class SubTable { public int Id {get; set;} public int ParentId {get; set;} }
public class Result { public int Id {get; set;} public string Title {get; set;} public int SubContentCount {get; set;} }
var p1 = new Parent() { Id = 1, Title = "Parent_1" };
var p2 = new Parent() { Id = 2, Title = "Parent_2" };
var p3 = new Parent() { Id = 3, Title = "Parent_3" };
var s1_1 = new SubTable() { Id = 11, ParentId = 1 };
var s1_2 = new SubTable() { Id = 12, ParentId = 1 };
var s1_3 = new SubTable() { Id = 13, ParentId = 1 };
var s2_1 = new SubTable() { Id = 21, ParentId = 2 };
var s2_2 = new SubTable() { Id = 22, ParentId = 2 };
var s3_1 = new SubTable() { Id = 31, ParentId = 3 };
var db_P = new List<Parent>() { p1, p2, p3 };
var db_S = new List<SubTable>() { s1_1, s1_2, s1_3, s2_1, s2_2, s3_1 };
public IEnumerable<Result> GetResults(string key = null)
{
var rows = from p in db_P
join s in db_S on p.Id equals s.ParentId into subContent
where string.IsNullOrEmpty(key) || p.Title.Contains(key)
select new Result() {
Id = p.Id,
Title = p.Title,
SubContentCount = subContent.Count()
};
return rows;
}
And example output (formatted onto multiple lines for readability)
> GetResults().ToList()
List<Submission#0.Result>(3) {
Submission#0.Result { Id=1, SubContentCount=3, Title="Parent_1" },
Submission#0.Result { Id=2, SubContentCount=2, Title="Parent_2" },
Submission#0.Result { Id=3, SubContentCount=1, Title="Parent_3" }
}
> GetResults("1").ToList()
List<Submission#0.Result>(1) {
Submission#0.Result { Id=1, SubContentCount=3, Title="Parent_1" }
}
>

LINQ Query to join three tables

I need a help in LINQ Query for the below.
public interface IBrand
{
int BrandId { get; set; }
IEnumerable<IBuyingAgency> BuyingAgencies { get; set; }
}
public interface IBuyingAgency
{
int BuyingAgencyId { get; set; }
}
public interface IClientGroup
{
IBuyingAgency BuyingAgency { get; set; }
int ClientGroupId { get; set; }
}
1). var brands = LoggedInUserHelper.GetUser().GetBrands(roles); // returns IEnumerable<Tuple<IBrand, string>>
2). var buyingAgencies = LoggedInUserHelper.GetUser().GetBuyingAgencies(roles); //IEnumerable<IBuyingAgency>
3). var clientGroups = LoggedInUserHelper.GetUser().GetClientGroups(roles); //IEnumerable<IClientGroup>
function IEnumerable<IClientGroup> GetClientGroups( List<int> BrandIds)
{
var brands = LoggedInUserHelper.GetUser().GetBrands(roles); // returns IEnumerable<Tuple<IBrand, string>>
var buyingAgencies = LoggedInUserHelper.GetUser().GetBuyingAgencies(roles); //IEnumerable<IBuyingAgency>
var clientGroups = LoggedInUserHelper.GetUser().GetClientGroups(roles); //IEnumerable<IClientGroup>
var lstBrandagencies = brands.Where(brand => BrandIds.Contains(brand.Item1.BrandId) && brand.Item1.BuyingAgencies.Any( ba => buyingAgencies.Contains(ba.BuyingAgencyId))).SelectMany(brand => brand.Item1.BuyingAgencies);
var buyingAgencyIDs = lstBrandagencies.Select(b => b.BuyingAgencyId);
clientGroups = clientGroups.Where(cg => buyingAgencyIDs.Contains(cg.BuyingAgency.BuyingAgencyId));
return Mapper.Map<IEnumerable<IClientGroup>>(clientGroups.ToList());
}
I wrote the above function but not working, it gets all the clientgroups instead of filtering
I wants to write a query to get all ClientGroups whch satisfies the below condition
1. retrieve the brand from brands ( above ) that matches the list of brandId's passing in as parameter
2. Than get all the buyingAgencies under brands (1) above which matches with the id's of (2) above
3. Finally get all clientgroups which matches with the buyingAgency retrieving in step (2)
Please can you help.
you are not filtering from your source 2) in this line
var buyingAgencyIDs = lstBrandagencies.Select(b => b.BuyingAgencyId);
just projecting from the previous query.
If I understood correctly you want to do this.
var lstBrandagencies = (from a in brands
where BrandIds.Contains(a.Item1.BrandId )
select a).SelectMany (b => b.Item1.BuyingAgencies )
.Select (b => b.BuyingAgencyId );
var buyingAgencyIDs = from a in buyingAgencies
where lstBrandagencies.Contains(a.BuyingAgencyId )
select a.BuyingAgencyId;
var clientGroupsResult = clientGroups.Where(cg => buyingAgencyIDs.Contains(cg.BuyingAgency.BuyingAgencyId));

Linq Unique Values

i have a list of generic class which consists of 2 string property and 1 List as a property
code snipnets is as follows:
public Class abc
{
public int ID { get; set; }
public String Name { get; set; }
List<String> myList;
public List<String> Subjects
{
get
{
if (myList == null)
{
myList = new List<string>();
}
return myList;
}
}
public abc()
{
}
public abc(int id, String name, params string[] subjects)
{
Subjects.AddRange(subjects.AsEnumerable<String>());
ID = id;
Name = name;
}
}
List<abc> myList = new List<abc>();
myList.Add(new abc(1, "p1", "Maths", "Science"));
myList.Add(new abc(2, "p2", "Maths", "Art"));
myList.Add(new abc(3, "p3", "Art", "Science"));
myList.Add(new abc(4, "p4", "Geometry", "Maths"));
I need the output as
Subject Count Person
Maths 3 p1,p2,p4
Science 2 p1,p3
Art 2 p2,p3
Geometry 1 p4
Looks like you want something like:
var query = from item in myList
from subject in item.Subjects
group item.Name by subject into g
select new { Subject = g.Key,
Count = g.Count(),
Person = string.Join(",", g) };
(Change g into g.ToArray() in the string.Join call if you're using .NET 3.5.)
var result =myList.SelectMany(p => p.Subjects
.Select(q => new{Person = p.Name, Subject = q, ID = p.ID}))
.GroupBy(p => p.Subject)
.Select(p => new {Name = p.Key, Count = p.Count(), Persons = p
.Aggregate("", (a, b) => a + b.Person
+ ",").TrimEnd(',')}).OrderBy( p => p.Count);
Iterate over this collection, and print result as needed - properties of a result are Name, Count, Persons

linq count/groupby not working

I want to group by the categoryid and then do a count on this. But I don't know how to do this. I have tried a couple of ways without success. Here is my latest:
public class Count
{
public int TradersCount { get; set; }
public int Id { get; set; }
public string Description { get; set; }
}
public IQueryable<Count> CountTradersAttachedToCategories()
{
var data = from tc in _db.tblTradersCategories
select new Count
{
Description = tc.tblCategory.description,
Id = tc.tblCategory.categoryId,
TradersCount = tc.Select(x => x.categoryid).GroupBy().Count()
};
return data;
}
tblTradersCategories joins both
tblTraders/tblCategories
A single trader can have many categories
A single category can have many traders
Thanks in advance for any help.
Clare
Try this:
var data = from tc in _db.tblTradersCategories
group tc by new { tc.tblCategory.categoryId,
tc.tblCategory.description } into g
select new { Count = g.Count(),
Id = g.Key.categoryId,
Description = g.Key.description };
If you want that in your Count class you may need to use AsEnumerable() to perform the conversion in process:
var converted = data.AsEnumerable()
.Select(c => new Count { TradersCount = c.Count,
Id = c.Id,
Description = c.Description });
You can try doing them all in one go:
var data = from tc in _db.tblTradersCategories
group tc by new { tc.tblCategory.categoryId,
tc.tblCategory.description } into g
select new Count { TradersCount = g.Count,()
Id = g.Key.categoryId,
Description = g.Key.description };
But I don't know if that will work. It depends on how the LINQ provider handles it.

How to dynamically choose two fields from a Linq query as a result

If you have a simple Linq query like:
var result = from record in db.Customer
select new { Text = record.Name,
Value = record.ID.ToString() };
which is returning an object that can be mapped to a Drop Down List, is it possible to dynamically specify which fields map to Text and Value?
Of course, you could do a big case (switch) statement, then code each Linq query separately but this isn't very elegant. What would be nice would be something like:
(pseudo code)
var myTextField = db.Customer["Name"]; // Could be an enumeration??
var myValueField = db.Customer["ID"]; // Idea: choose the field outside the query
var result = from record in db.Customer
select new { Text = myTextField,
Value = myValueField };
Right way to do this is with closures.
Func<Customer, string> myTextField = (Customer c) => c["Name"];
Func<Customer, int> myValueField = (Customer c) => c["ID"];
var result = from record in db.Customer
select new { Text = myTextField(record),
Value = myValueField(record) };
The one limitation is that your definition of myTextField always needs to return a string.
You could try something like
class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
var dict = new Dictionary<string, Func<Customer, string>>
{ { "ID", (Customer c) => c.ID.ToString() },
{ "Name", (Customer c) => c.Name},
{ "Surname", (Customer c) => c.Surname } };
List<Customer> rows = new List<Customer>();
rows.Add(new Customer { ID = 1, Name = "Foo", Surname = "Bar"});
var list = from r in rows
select new { Text = dict["ID"](r), Value = dict["Name"](r) };
To try to access the properties dynamically, you could try something like
var dict = new Dictionary<string, Func<Customer, string>>
{ { "ID", (Customer c) => c.GetType().GetProperty("ID").GetValue(c,null).ToString() },
{ "Name", (Customer c) => c.GetType().GetProperty("Name").GetValue(c,null).ToString()},
{ "Surname", (Customer c) => c.GetType().GetProperty("Surname").GetValue(c,null).ToString() } };

Resources