LINQ | How do I get SUM without grouping? - linq

Crazy question...however, I want the sum of all the rows in a table for a column (without using the group by clause)
Example:
Table = Survey
Columns = Answer1, Answer2, Answer3
1 1 1
4 3 5
3 3 2
I want the sums for each column.
Final results should look like:
Answer1Sum Answer2Sum Answer2Sum
8 7 8
This doesn't work:
from survey in SurveyAnswers
select new
{
Answer1Sum = survey.Sum(),
Answer2Sum = survey.Sum(),
Answer3Sum = survey.Sum()
}

Would this work:
var answer1Sum = SurveyAnswers.Sum( survey => survey.Answer1 );
var answer2Sum = SurveyAnswers.Sum( survey => survey.Answer2 );
var answer3Sum = SurveyAnswers.Sum( survey => survey.Answer3 );

A VB.NET soltuion to this answer for anyone that needs it is as follows:
Dim Answer1Sum = SurveyAnswers.Sum(Function(survey) survey.Answer1)
Dim Answer2Sum = SurveyAnswers.Sum(Function(survey) survey.Answer2)
Dim Answer3Sum = SurveyAnswers.Sum(Function(survey) survey.Answer3)

SurveyAnswers.Sum(r => r.Answer1);

Related

How to find all rows of items that have a part in common using LINQ?

I need to return all records (items) that has a part (X) so I can use that in a group or .GroupBy afterwards
Using this summary data:
ItemName PartName
1 A
1 B
2 A
3 C
So Item1 has two parts (A,B), etc...
I need a LINQ query that will
- find all items that have part A (i.e items 1 and 2)
- return all rows for all these items
1 A
1 B
2 A
Notice that the end result returned the row (1 B) because Item1 has PartA and so I need to get back all rows for Item1.
I was looking at something like:
let items = from data in summary where data.PartName == A select new { data.ItemName } // to get all the items I need
But then, now that I have that list I need to use it to get all the rows for all items listed, and I can't seem to figure it out ...
Actual Source Code (for reference):
NOTE:
Recipe = ITEM
Ingredient = PART
(I was just trying to make it simpler)
ViewFullRecipeGrouping = (
from data in ViewRecipeSummary
group data by data.RecipeName into recipeGroup
let fullIngredientGroups = recipeGroup.GroupBy(x => x.IngredientName)
select new ViewFullRecipe()
{
RecipeName = recipeGroup.Key,
RecipeIngredients = (
from ingredientGroup in fullIngredientGroups
select new GroupIngredient()
{
IngredientName = ingredientGroup.Key
}
).ToList(),
ViewGroupRecipes = (
from data in ViewRecipeSummary
// this is where I am looking to add the new logic to define something I can then use within the next select statement that has the right data based on the information I got earlier in this query.
let a = ViewRecipeSummary.GroupBy(x => x.RecipeName)
.Where(g => g.Any(x => x.IngredientName == recipeGroup.Key))
.Select(g => new ViewRecipe()
{
RecipeName = g.Key,
IngredientName = g.Select(x => x.IngredientName)
})
select new GroupRecipe()
{
// use the new stuff here
}).ToList(),
}).ToList();
Any help would be much appreciated.
Thanks,
I believe this does what you want:
var data = /* enumerable containing rows in your table */;
var part = "X";
var items = new HashSet<int>(data
.Where(x => x.PartName == part)
.Select(x => x.ItemName));
var query = data.Where(x => items.Contains(x.ItemName));
If I understand your comment at the end, I believe this also does what you want:
var query = data
.GroupBy(x => x.ItemName)
.Where(g => g.Any(x => x.PartName == part))
.Select(g => new
{
ItemName = g.Key,
PartNames = g.Select(x => x.PartName)
});

VB.NET filtering/grouping a datatable

Sample Scenario
I have a table in a database with the following fields:- SerialNo, GroupNo, Description, Quantity. At the moment I am cycling around a DataTable which has been populated from an ADO.NET DataSet and I am adding the fields into a List as follows...
' Gets the items from the database and created a DataSet
' The DataSet has a named DataTable called MyTable
ds = GetItems
' Item is an model in my MVC project
Dim Item As Item
' I am creating a List of items...
i As List(Of Item)
For Each row As DataRow In ds.Tables("MyTable").Rows
Item = New Item() With {
.SerialNo = If(Not IsDBNull(row("SerialNo")), CInt(row("SerialNo")), 0),
.GroupNo = If(Not IsDBNull(row("GroupNo")), CStr(row("GroupNo")), ""),
.Description = If(Not IsDBNull(row("Description")), CStr(row("Description")), ""),
.Quantity = If(Not IsDBNull(row("Quantity")), CInt(row("Quantity")), 0)
}
ai.Add(Item)
Next
Requirement
Instead of getting every row I want to get just the first occurence of every GroupNo and return this result into a List. For example...
SerialNo = 1 GroupNo = 1 Description = Item A Quantity = 100
SerialNo = 2 GroupNo = 1 Description = Item B Quantity = 100
SerialNo = 3 GroupNo = 1 Description = Item C Quantity = 100
SerialNo = 4 GroupNo = 2 Description = Item D Quantity = 100
SerialNo = 5 GroupNo = 2 Description = Item E Quantity = 100
SerialNo = 6 GroupNo = 3 Description = Item F Quantity = 100
... should actually be modified to return...
SerialNo = 1 GroupNo = 1 Description = Item A Quantity = 100
SerialNo = 4 GroupNo = 2 Description = Item D Quantity = 100
SerialNo = 6 GroupNo = 3 Description = Item F Quantity = 100
I am using Visual Studio 2010 (VB.NET) with .NET 4.0.
I've tried to research various ways but I either come stuck trying to extract all 4 columns doesn't seem to group correctly. Note: I don't want to modify the query to only return the subset of data. I need to filter/group it with code.
So you just want to take the first DataRow of each group to initialize your Item:
Dim items = From row In ds.Tables("MyTable").AsEnumerable()
Let GroupNo = row.Field(Of Int32)("GroupNo")
Group row By GroupNo Into Group
Select New Item() With {
.GroupNo = GroupNo,
.SerialNo = Group.First().Field(Of Int32)("SerialNo"),
.Quantity = Group.First().Field(Of Int32)("Quantity"),
.Description = Group.First().Field(Of String)("Description")
}
If you want to copy it into a List(Of Item) you only have to call items.ToList().

How to .GroupBy multiple columns LINQ/Projection?

How can I group by multiple columns using linq projection?
Something like this:
var q = db.Areas.GroupBy(x => x.AreaCatId, x.AreaCatName, x.AreaId, x.AreaName);
Resulting in a flat result set such as:
AreaCatId, AreaCatName, AreaId, AreaName
0 US 1 FL
0 US 2 NY
1 Canada 3 BC
You can GroupBy an anonymous type:
var q = db.Areas.GroupBy(
x => new
{
CatId = x.AreaCatId,
CatName = x.AreaCatName,
Id = x.AreaId,
Name = x.AreaName
});

how do I use linq to dataSet to convert dataTable to an array?

I have the following sql table schema:
procudtId productPrice Color
==================================
1 3 $ Blue
1 3 $ Red
1 3 $ Green
2 5 $ Blue
2 5 $ Red
Using c# code I got this into dataSet.
How can I use linq to dataSet to build an array that looks like
[ price:"3$", ColorList:<"Blue","Red","Green"> ;
price:"5$", ColorList:<"Blue","Red">]
Thanks
I think this will work:
//dt is the DataTable you're working with.
var groups = from row in dt.AsEnumerable()
group row["Color"] by row["productPrice"] into prices
select prices;
var query = from g in groups
select new
{
price = g.Key,
ColorList = g.ToList()
};
If that doesn't do it, let me know and I'll edit.
I think I'll do this in two steps:
1. create the color lists
var dataRows = from row in ds.Tables[0].AsEnumerable()
//group row by row.Field<Int32>("TierId")
where row.Field<Int32>("ProductId") == 1
select
row.Field<String>("Color");
List<String> list = dataRows.ToList();
2. acquire the product price
3. combine them both to array

Removing values from a returned linq query

HI there I am hoping for some help with a query I have.
I have this query
var group =
from r in CustomerItem
group r by r.StoreItemID into g
select new { StoreItemID = g.Key,
ItemCount = g.Count(),
ItemAmount = Customer.Sum(cr => cr.ItemAmount),
RedeemedAmount = Customer.Sum(x => x.RedeemedAmount)
};
I am returning my results to a list so I can bind it listbox.
I have a property called EntryType which is an int. There are 2 available numbers 1 or 2
Lets say I had 3 items that my query is working with
2 of them had the EntryType = 1 and the 3rd had EntryType2. The first records had a ItemAmount of 55.00 and the 3rd had a ItemAmount of 50.00
How can I group using something simlar to above but minus the ItemAmount of 50.00 from the grouped amount to return 60.00?
Any help would be great!!
It's not really clear what the question is - are you just trying to ignore all items with an entry type of 2? To put it another way, you only want to keep entries with an entry type of 1? If so, just add a where clause:
var group = from r in CustomerItem
where r.EntryType == 1
group r by r.StoreItemID into g
select new {
StoreItemID = g.Key, ItemCount = g.Count(),
ItemAmount = Customer.Sum(cr => cr.ItemAmount),
RedeemedAmount = Customer.Sum(x => x.RedeemedAmount)
};
Change ItemAmount = ... to:
ItemAmount =
g.Where(x => x.EntryType == 1).Sum(cr => cr.ItemAmount) -
g.Where(x => x.EntryType == 2).Sum(cr => cr.ItemAmount),
I changed Customer to g because this seems to be an error, but it's not clear to me from your question what you mean here, so maybe this change is not what you want.
A slightly more concise method is to use test the entry type in the sum and use the ternary operator to choose whether to add the positive or negative value:
ItemAmount = g.Sum(cr => cr.EntryType == 1 ? cr.ItemAmount : -cr.ItemAmount),
This gives the value of 60.00 as you required.

Resources