Grouping data with sum - linq

I have the following list:
mat.Add(new Material() { ID = 1, ProdName = "Cylinder", Weight=23, Discontinued='N' });
mat.Add(new Material() { ID = 2, ProdName = "Gas", Weight = 25, Discontinued='N' });
mat.Add(new Material() { ID = 3, ProdName = "Match", Weight = 23, Discontinued='N' });
I want a result as:
2 Products have Weight 23 and Discontinued N
1 Product have Weigth 25 Discontinued N

It's not clear exactly what you're actually grouping by - is it both weight and the discontinued status? If so, you can just do:
var query = mat.GroupBy(material =>
new { material.Weight, material.Discontinued });
foreach (var result in query)
{
Console.WriteLine("{0} products have {1}", result.Count(), result.Key);
}

"just" group by Weight and Discontinued.
something like :
var result = mat.GroupBy(a=>new{a.Weight,a.Discontinued}).Select(b=>new b.Key.Weight,b.Key.Discontinued,Count = b.Count()});

Got it!
.GroupBy(re => new { re.Weight, re.Discontinued })
.Select(grp => new { CXXX = group.Key, Count = grp.Count()

Related

C# Linq how to use group by to get the desired output

I have the following classes
public class Product
{
public string PNo {get;set;}
public String GCode {get;set;}
public IList<Detail> Details {get;set;}
}
public class Detail{
public string Color {get;set;}
public string Size {get;set;}
}
And i have the data in an array as below
PNO GCode Color Size Amount
12345 GCC A L 1
12345 GCC V M 2
12345 GCC C S 3
12345 GCC D XL 4
12345 GCC E XS 5
How do i get the following output using groupby so that my output could like shown below
Expected output:
{
PNO: 12345,
GCode: GCC,
options:[
{Color:A, Size:L, Amount: 1},
{Color:V, Size:M, Amount: 2},
{Color:C, Size:S, Amount: 3},
{Color:D, Size:XL, Amount: 4},
{Color:E, Size:XS, Amount: 5}
]
}
Thanks
Given the contract you defined. I think below code snippet is OK to generate the JSON you want, I use anonymous object a lot, you can replace with you entity class.
products.GroupBy(product => new
{
product.PNo,
product.GCode
})
.Select(productGroup => new
{
productGroup.Key.PNo,
productGroup.Key.GCode,
options = productGroup.SelectMany(product => product.Details.Select(detail => new
{
detail.Color,
detail.Size,
detail.Amount
}))
});
Hope it helps.
This will get you that expected output:
Query Syntax:
var result = (from item in collection
group item by new { item.PNO, item.GCode } into grouping
select new Product
{
PNo = grouping.Key.PNO,
GCode = grouping.Key.GCode,
Details = grouping.Select(item => new Detail { Color = item.Color, Size = item.Size, Amount = item.Amount }).ToList()
}).ToList();
Method Syntax:
var result = collection.GroupBy(item => new { item.PNO, item.GCode })
.Select(grouping => new Product
{
PNo = grouping.Key.PNO,
GCode = grouping.Key.GCode,
Details = grouping.Select(item => new Detail { Color = item.Color, Size = item.Size, Amount = item.Amount }).ToList()
}).ToList();
Test Data:
List<dynamic> collection = new List<dynamic>()
{
new { PNO = "12345", GCode = "GCC", Color = "A", Size="L", Amount=1 },
new { PNO = "12345", GCode = "GCC", Color = "V", Size="M", Amount=2 },
new { PNO = "12345", GCode = "GCC", Color = "C", Size="S", Amount=3 },
new { PNO = "12345", GCode = "GCC", Color = "D", Size="XL", Amount=4 },
new { PNO = "12345", GCode = "GCC", Color = "E", Size="XS", Amount=5 },
};

Getting the value of Parent control in Google visualization CategoryFilter

I have a sample fiddle here in which the Google visualization Category Filter control is created as,
var countryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control1',
'options': {
'filterColumnIndex': 0,
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
var regionPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control2',
'options': {
'filterColumnIndex': 1,
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
var cityPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control3',
'options': {
'filterColumnIndex': 2,
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
Here We can select the filter in any combination. But, If I directly select Albany in CityPicker control then, how can I get its parent's values (ie, The value USA from countryPicker and the value New York from regionPicker) in which that particular city belongs to?
You can use a statechange event handler to get the current city, and then filter the DataTable by city to get the region and country combo(s) that correspond to that city. Here's an example:
google.visualization.events.addListener(cityPicker, 'statechange', function () {
var state = cityPicker.getState();
if (state.selectedValues.length) {
// there is a selected city
// since you set allowMultiple to false, there can be only one, so it is safe to do this:
var city = state.selectedValues[0];
var rows = data.getFilteredRows([{column: 2, value: city}]);
// parse the rows for all country/region/state combos
var regionsCountries = [];
var comboChecker = {};
for (var i = 0; i < rows.length; i++) {
var country = data.getValue(rows[i], 0);
var region = data.getValue(rows[i], 1);
// the comboChecker makes sure we don't add a region/country combo more than once to the data set
if (!comboChecker[region + country]) {
comboChecker[region + country] = true;
regionsCountries.push({region: region, country: country});
}
}
// do something with regionsCountries
}
});
See working example here: http://jsfiddle.net/asgallant/KLhD3/1/

LINQ Grouping or Splitting

Im having an issue doing something thats probably pretty simple.
My LINQ query is returning a result set of 10 objects.
Something like:
Name: Bill, Action: aaa, Id: 832758
Name: Tony, Action: aaa, Id: 82fd58
Name: Bill, Action: bbb, Id: 532758
Name: Tony, Action: bbb, Id: 42fd58
What I need to do, is to group these so that there are only 2 rows, ie one per Name, but have the ones with "Action: bbb" move into a different column. So the output would be:
Name: Bill, Action: aaa, Action_2: bbb, Id: 832758, Id_2: 532758
Name: Tony, Action: aaa, Action_2: bbb, Id: 82fd58, Id_2: 42fd58
Can anyone explain to me how I might do that?
Cheers
var myData = new []
{
new { Name = "Bill", Action="aaa", Id = "832758" },
new { Name = "Tony", Action="aaa", Id = "82fd58" },
new { Name = "Bill", Action="bbb", Id = "532758" },
new { Name = "Tony", Action="bbb", Id = "42fd58" }
};
var result = myData
.GroupBy(x=>x.Name)
.Select(g=>new
{
Name = g.Key,
Action = g.First().Action,
Action_2 = g.Last().Action,
Id = g.First().Id,
Id_2 = g.Last().Id
});
The query above assumes that you have only two rows for each name; if you have multiple rows per name, you can take the second Action/Id value by using .Skip(1).Take(1) instead of .Last()
I don't think there's a real simple way to do it. I've connocted this, though, which might get you started:
var myData = new []
{
new { Name = "Bill", Action="aaa", Id = "832758" },
new { Name = "Tony", Action="aaa", Id = "82fd58" },
new { Name = "Bill", Action="bbb", Id = "532758" },
new { Name = "Tony", Action="bbb", Id = "42fd58" }
};
// group all the Names together
var result = from m in myData
group m by m.Name into names
orderby names.Key
select names;
// go through each Name group and create the output string to store in sbLines
var sbLines = new StringBuilder();
foreach (var name in result)
{
var sb = new StringBuilder();
sb.AppendFormat("Name: {0}, ", name.Key);
int count = 1;
foreach (var item in name)
{
if(count > 1)
sb.AppendFormat("Action_{0}: {1}, ", count, item.Action);
else
sb.AppendFormat("Action: {0}, ", item.Action);
count++;
}
count = 1;
foreach (var item in name)
{
if(count > 1)
sb.AppendFormat("Id_{0}: {1}, ", count, item.Id);
else
sb.AppendFormat("Id: {0}, ", item.Id);
count++;
}
sbLines.Append(sb.ToString().Trim(new char[] { ' ',',' }));
sbLines.Append(Environment.NewLine);
}
Console.WriteLine(sbLines.ToString());
Run it here: http://ideone.com/8UTxr

How to project simple data set into to anonymous type of a different shape

I have a simple set of data that I am having trouble figuring out how to create the projection I want using LINQ.
public class Score {
public string Name { get; set; }
public int Value { get; set; }
}
var scores = new List<Score> {
new Score { Name = "jesse", Value = 10 },
new Score { Name = "jesse", Value = 12 },
new Score { Name = "jesse", Value = 15 },
new Score { Name = "billy", Value = 5 },
new Score { Name = "billy", Value = 7 },
new Score { Name = "billy", Value = 20 },
new Score { Name = "colin", Value = 25 },
new Score { Name = "colin", Value = 13 },
new Score { Name = "colin", Value = 8 }
};
I need to project 'scores' into an anonymous type with the following structure.
{
series : [
{ name : "jesse", data : [10, 12, 15 ] },
{ name : "billy", data : [ 5, 7, 20 ] },
{ name : "colin", data : [25, 13, 8 ] }
]
}
Any help is appreciated.
var result = new {
series = from score in scores
group score.Value by score.Name into nameValues
select new
{
name = nameValues.Key,
data = nameValues
}
};
Does this match the structure you want?
var query = scores.GroupBy(s => s.Name);
var result = query.Select(q => new {
Name = q.Key,
Data = q.ToArray().Select(k => k.Value)
});
var anotherAnon = new {series = result.ToArray()};

Linq to Entities - limiting the results of a search form to only those results that match all choices for a many to many relationship

I have 3 tables in my application
Employee
EmployeeID
EmployeeName
DOB
Skills
SkillID
Description
EmployeeSkills
EmployeeID
SkillID
YearsExperience
What's the best way to write a linq query to allow a user to simultaneously search on information in the Employee table and limit the results to those who match all skills chosen? I've got no problem when it's one skill, or any skill out of those chosen, but I'm stuck on how to only return when they match all. The best I've managed so far is a hideous mass of intersects.
You could loop over the sleected skills, then add a Where(x=>x.Skills.Contails(skill)) to the query for each skill requested. This will eliminate each employee that doesn't have every skill.
Here is the solution I came up with using a very simple version of your table structure:
var q = from e in Employee
join es in EmployeeSkills
on e.EmployeeID equals es.EmployeeID
join s in Skills
on es.SkillID equals s.SkillID
group s by e into grouping
where !skillsToMatch.Except(grouping.Select(x => x.SkillID)).Any()
select grouping.Key;
Where 'skillsToMatch' is an IEnumerable of SkillID's you want the Employee's to have. It will return all Employees that at least have all the skills in 'skillsToMatch'.
If you have linqpad installed you can see how this works with my dummy data with this script:
var Employee = new [] {
new { EmployeeID = 1 },
new { EmployeeID = 2 },
new { EmployeeID = 3 },
new { EmployeeID = 4 },
new { EmployeeID = 5 },
};
var Skills = new [] {
new { SkillID = 1 },
new { SkillID = 2 },
new { SkillID = 3 },
new { SkillID = 4 },
new { SkillID = 5 },
};
var EmployeeSkills = new [] {
new { EmployeeID = 1, SkillID = 4 },
new { EmployeeID = 1, SkillID = 5 },
new { EmployeeID = 3, SkillID = 4 },
new { EmployeeID = 3, SkillID = 1 },
new { EmployeeID = 5, SkillID = 3 },
};
var skillsToMatch = new [] { 4, 5 };
var q = from e in Employee
join es in EmployeeSkills
on e.EmployeeID equals es.EmployeeID
join s in Skills
on es.SkillID equals s.SkillID
group s by e into grouping
where !skillsToMatch.Except(grouping.Select(x => x.SkillID)).Any()
select grouping.Key;
q.Dump();
Play around by changing the 'skillsToMatch' array to see if it provides the behavior you seek.

Resources