How to make a LINQ query for this? - c#

Okay, stuck for a day now, please somebody give a helping hand!
I want to select the quantity of EVERY possible item that a specific customer has, regardless of whether they have ordered the item or not. So if they haven't ordered it (i.e. it is not in the Orders table) then return a value of 0 for the quantity.
Orders CustomerId ItemId Quantity
Items
ItemId
ItemName
Customers
CustomerId
CustomerName
I'm guessing that this will involve some kind of subquery, but really not sure.
from c in customers
join o in Orders
on c.CustomerId == o.CustomerId
select c.CustomerName, o.Quantity
where c.CustomerId == customerId

This one caught my interest so I wrote a console app to do it.
Andomar answered a few moments before I did (+1) from me.
This is my independent solution but very close to his and no simpler...
class Program {
private class CustomerDto {
public int CustomerId { get; set; }
public string CustomerName { get; set; }
}
private class ItemDto {
public int ItemId { get; set; }
public string ItemName { get; set; }
}
private class OrderDto {
public int Id { get; set; }
public int ItemId { get; set; }
public int CustomerId { get; set; }
public int Quantity { get; set; }
}
private class CustomerOrderDto {
public int CustomerId { get; set; }
public int ItemId { get; set; }
public int TotalQuantity { get; set; }
}
static void Main(string[] args) {
List<CustomerDto> Customers = new List<CustomerDto>() {
new CustomerDto() { CustomerId = 1, CustomerName = "one"},
new CustomerDto() { CustomerId = 2, CustomerName = "two"},
new CustomerDto() { CustomerId = 3, CustomerName = "three"}
};
List<ItemDto> Items = new List<ItemDto>() {
new ItemDto() { ItemId = 1, ItemName = "item one"},
new ItemDto() { ItemId = 2, ItemName = "item two"},
new ItemDto() { ItemId = 3, ItemName = "item three"}
};
// customer1 has 2 orders for item 1, 0 for item 2 or 3
// customer2 has 1 order for item 2, 0 for item 1 or 3
// customer3 has 1 order for item 2, 1 order for item 3 and 0 for item 1
List<OrderDto> Orders = new List<OrderDto>() {
new OrderDto() { Id = 1, CustomerId = 1, ItemId = 1, Quantity = 3 },
new OrderDto() { Id = 1, CustomerId = 1, ItemId = 1, Quantity = 5 },
new OrderDto() { Id = 1, CustomerId = 3, ItemId = 2, Quantity = 5 },
new OrderDto() { Id = 1, CustomerId = 3, ItemId = 3, Quantity = 5 },
new OrderDto() { Id = 1, CustomerId = 2, ItemId = 2, Quantity = 5 }
};
List<CustomerOrderDto> results = (from c in Customers
from i in Items
join o in Orders on
new { c.CustomerId, i.ItemId } equals
new { o.CustomerId, o.ItemId } into oj
from o in oj.DefaultIfEmpty()
let x = o ?? new OrderDto() { CustomerId = c.CustomerId, ItemId = i.ItemId, Quantity = 0 }
group x by new { x.CustomerId, x.ItemId } into g
select new CustomerOrderDto() {
CustomerId = g.Key.CustomerId,
ItemId = g.Key.ItemId,
TotalQuantity = g.Select(x => x.Quantity).Sum()
}
).ToList();
foreach (var result in results) {
Console.WriteLine("Customer {0} purchased {1} units of item {2}",
result.CustomerId, result.TotalQuantity, result.ItemId);
}
Console.ReadKey(true);
}
}

In SQL, this is quite simple:
select c.name
, i.name
, isnull(sum(o.quantity),0)
from customers c
cross join
items i
left join
orders o
on o.customerid = c.customerid
and o.itemid = o.itemid
group by
c.name
, i.name
Translated to LINQ, this becomes:
from c in Customers
from i in Items
join o in Orders
on new { c.Customerid, i.Itemid }
equals new { o.Customerid, o.Itemid }
into o1
from o2 in o1.DefaultIfEmpty()
group o2.Quantity
by new { CustomerName = c.Name, ItemName = i.Name }
into q
select new {
q.Key.CustomerName,
q.Key.ItemName,
Quantity = q.Sum() ?? 0
}
I hope someone else posts a simpler LINQ version, because this looks insanely complex :)

The LINQ expresssion
from c in Customers
from i in Items
select ...
is a cross join of all customers and items. So the only thing left to do is to sum up the quantities for each:
var result = from c in Customers
from i in Items
select new
{
Customer = c,
Item = i,
Quantity = (from o in Orders
where o.CustomerId == c.CustomerId && o.ItemId == i.ItemId
select o.Quantity).Sum(),
};
Note that Sum returns 0 for an empty IEnumerable<int> (i.e. no orders found).

Linq
from t in Customers
join t2 in Orders on t.CustomerId equals (int)t2.CustomerId into t2Join
from t2 in t2Join.DefaultIfEmpty()
group t by t into t_g
select new
{
CustomerId = t_g.Key.CustomerId,
OrdersId = t_g.Key.OrdersId,
Quantity = t_g.Key.Orders.Where(c => c.CustomerId == t_g.Key.CustomerId)
.Sum(c => c.Quantity)
};
This is not tested but you can try.

Related

ASP.NET-MVC4 - Linq query to select largest "supplier" in a database

i have 2 tables in a database
supplier table: SupplierID - SupplierName
product table: ProductID - ProductName - UnitsInStock - SupplierID
how can i select the supplier that has largest UnitsInStock?
here's the code i have
private storeDBEntities2 db1 = new storeDBEntities2();
public ActionResult Index()
{
var product = db1.Products.Where(e => e.UnitsInStock == 0);
var largestSupplier = db1.Products.GroupBy(e => e.SupplierID);
Product minimord = db1.Products.OrderBy(e => e.UnitsOnOrder).FirstOrDefault();
var supplier = // this is the query i am struggling with
AllModelsProduct all = new AllModelsProduct { Iproduct = product.ToList(), product = new Product(),largestSupplierOfTheStore = supplier,minimumOrders = minimord };
return View(all);
}
here's a picture of my data
i need to get supplierID 345 as we have 20 units belong to him in store which is greater than the other supplier with 5 + 3 + 0 = 8 units
If all you're looking to do is find the supplier with the largest number of UnitsInStock then this should do the trick.
I have created a dotNetFiddle for you to observe.
But here it is anyway:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
List<Supply> lstSuppliers = new List<Supply>();
Supply supply1 = new Supply() { ID = 1, SupplierName = "Supplier One"};
Supply supply2 = new Supply() { ID = 2, SupplierName = "Supplier Two"};
lstSuppliers.Add(supply1);
lstSuppliers.Add(supply2);
Product product1 = new Product() {ID = 1, UnitsInStock = 3, SupplierID = 1};
Product product2 = new Product() {ID = 2, UnitsInStock = 3, SupplierID = 2};
Product product3 = new Product() {ID = 3, UnitsInStock = 5, SupplierID = 1};
List<Product> lstAllProducts = new List<Product>();
lstAllProducts.Add(product1);
lstAllProducts.Add(product2);
lstAllProducts.Add(product3);
var findSupplierId = lstAllProducts.GroupBy(x => x.SupplierID).Select(x => new{ Supplier = x.Key.ToString(), Count = x.Sum(g => g.UnitsInStock)}).OrderByDescending(x => x.Count).First().Supplier;
Console.WriteLine(findSupplierId);
Console.WriteLine(lstSuppliers.Single(x => x.ID.ToString() == findSupplierId).SupplierName);
}
}
public class Supply{
public int ID {get;set;}
public string SupplierName {get;set;}
}
public class Product{
public int ID {get;set;}
public int UnitsInStock {get;set;}
public int SupplierID {get;set;}
}
This uses the GroupBy, along with creating anonymous classes to get the desired outcome.
Let me know if this helps!
Update - To show if multiple suppliers have the same units in stock
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
List<Supply> lstSuppliers = new List<Supply>();
Supply supply1 = new Supply() { ID = 1, SupplierName = "Supplier One"};
Supply supply2 = new Supply() { ID = 2, SupplierName = "Supplier Two"};
Supply supply3 = new Supply() { ID = 3, SupplierName = "Supplier Three"};
lstSuppliers.Add(supply1);
lstSuppliers.Add(supply2);
lstSuppliers.Add(supply3);
Product product1 = new Product() {ID = 1, UnitsInStock = 3, SupplierID = 1};
Product product2 = new Product() {ID = 2, UnitsInStock = 3, SupplierID = 2};
Product product3 = new Product() {ID = 3, UnitsInStock = 5, SupplierID = 1};
Product product4 = new Product() {ID = 4, UnitsInStock = 8, SupplierID = 3};
List<Product> lstAllProducts = new List<Product>();
lstAllProducts.Add(product1);
lstAllProducts.Add(product2);
lstAllProducts.Add(product3);
lstAllProducts.Add(product4);
// finds largest supplier
//var findSupplierId = lstAllProducts.GroupBy(x => x.SupplierID).Select(x => new{ Supplier = x.Key.ToString(), Count = x.Sum(g => g.UnitsInStock)}).OrderByDescending(x => x.Count).First().Supplier;
//Console.WriteLine(lstSuppliers.Single(x => x.ID.ToString() == findSupplierId).SupplierName);
// What if there are multiple suppliers with the same number of units in stock?
// first - we have to find the largest number of units in stock
var findLargestNumberUIS = lstAllProducts.GroupBy(x => x.SupplierID).Select(x => new{ Supplier = x.Key.ToString(), Count = x.Sum(g => g.UnitsInStock)}).Max(x => x.Count); // 8
// second - gather a list of suppliers where their units in stock == findLargestNumberUIS
var lstOfLargestSuppliers = lstAllProducts.GroupBy(x => x.SupplierID).Select(x => new{ Supplier = x.Key.ToString(), Count = x.Sum(g => g.UnitsInStock)}).Where(x => x.Count == findLargestNumberUIS).ToList();
// third - loop through lstOfLargestSuppliers to get all suppliers that have the same amount of units in stock which happen to be the largest
foreach(var item in lstOfLargestSuppliers){
var supplier = lstSuppliers.Single(x => x.ID.ToString() == item.Supplier).SupplierName;
Console.WriteLine(supplier); // print the supplier names to console
// Output - Supplier One
// Supplier Three
}
}
}
public class Supply{
public int ID {get;set;}
public string SupplierName {get;set;}
}
public class Product{
public int ID {get;set;}
public int UnitsInStock {get;set;}
public int SupplierID {get;set;}
}

Cannot group data in LINQ

I have a question about a LINQ grouping.
I thought that grouping would be a simple matter of using the GroupBy function on the result set and specifying what to group it by. However my items appear to not be grouping together and instead are displaying as if the GroupBy function wasn't there. I want to group by the itemPk, but I'm can't seem to do it. I have tried grouping by both category.ItemFk and Item.Itempk, but no luck. Could someone give me a pointer on this?
var itemIds = items.Select(i => i.ItemId).ToList();
var itemAndCatJoin =
from item in Context.SCS_Items
join category in Context.SCS_ItemCategories
on item.ItemPk equals category.ItemFk
into temp
from category in temp.DefaultIfEmpty()
select new ExportItemTable
{
Category = category,
Item = item
};
return itemAndCatJoin.Where(i => itemIds.Contains(i.Item.ItemPk))
.GroupBy(n => new {n.Item, n.Category})
.Select(i => new ExportableItem
{
ItemPk = i.Key.Item.ItemPk,
Name = i.Key.Item.Name,
Description = i.Key.Item.Description,
Price = i.Key.Item.Price,
Category = i.Key.Category.Category.Category_Name,
GLDepartment = i.Key.Category.GL_Department.Name ?? "",
GLName = i.Key.Category.GL_Name.Name ?? "",
StartDate = i.Key.Item.StartDate,
EndDate = i.Key.Item.EndDate,
FiscalYear = i.Key.Item.SCS_FiscalYear.Name,
School = i.Key.Item.School != null ? i.Key.Item.School.School_Name : i.Key.Item.Board.Board_Name,
Beneficiary = i.Key.Item.SCS_Beneficiary.Name,
Quantity = i.Key.Item.MaxQuantity,
Deleted = i.Key.Item.DeletedFlag,
OptionalStudents = i.Key.Item.SCS_Attachments.Where(a => !a.IsRequired).SelectMany(a => a.SCS_StudentAttachments).Where(s => !s.DeletedFlag).Select(s => s.StudentFk).Distinct().Count(),
RequiredStudents = i.Key.Item.SCS_Attachments.Where(a => a.IsRequired).SelectMany(a => a.SCS_StudentAttachments).Where(s => !s.DeletedFlag).Select(s => s.StudentFk).Distinct().Count(),
IsPublic = i.Key.Item.IsPublic,
AllowRecurring = i.Key.Item.AllowRecurringPayments,
EffectiveCutoff = i.Key.Item.SCS_Attachments.Where(a => !a.DeletedFlag && a.CourseDropCutoff.HasValue).Select(a => a.CourseDropCutoff).OrderBy(a => a).FirstOrDefault(),
CreatedDate = i.Key.Item.CreatedDate
}).OrderBy(i => i.ItemPk).ToList();
}
your groupbyy is indeed doing nothing for you, you need to tell the groupby what to group by....
like
.GroupBy(n => n.Category)
Here is a simple example to your grouping question:
class Program
{
static void Main()
{
var allItems = GetAllItems();
var groups = from item in allItems
group item by item.Category
into newGroup
select newGroup;
foreach (var group in groups)
{
Console.WriteLine($"\nCategory: {group.Key}");
foreach (var item in group)
{
Console.WriteLine($"{item.Name}: {item.Price}");
}
}
Console.ReadLine();
}
static List<Category> GetAllCategories()
{
return new List<Category>()
{
new Category() { Id = 1, Name = "Programming Books" },
new Category() { Id = 2, Name = "Fiction Books" }
};
}
static List<Item> GetAllItems()
{
return new List<Item>()
{
new Item() { Id = 1, Name = "Embedded Linux", Category = 1, Price = 9.9 },
new Item() { Id = 2, Name = "LINQ In Action", Category = 1, Price = 36.19 },
new Item() { Id = 3, Name = "C# 6.0 and the .NET 4.6 Framework", Category = 1, Price = 40.99 },
new Item() { Id = 4, Name = "Thinking in LINQ", Category = 1, Price = 36.99 },
new Item() { Id = 5, Name = "The Book Thief", Category = 2, Price = 7.99 },
new Item() { Id = 6, Name = "All the Light We Cannot See", Category = 2, Price = 16.99 },
new Item() { Id = 7, Name = "The Life We Bury", Category = 2, Price = 8.96 }
};
}
}
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public int Category { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
This example is simple enough for anyone new to LINQ. I am sure you can make some adjustment to make it work for your specific issue. Hope this will help.

Doing multiple joins within a LINQ statement

Can someone help me translate the following SQL query into a LINQ format.
SELECT a.ID,
a.HostID,
h.URL,
a.SourceURL,
a.TargetURL,
c.Value,
a.ExtFlag
FROM Link a
INNER JOIN Host h
ON h.ID = a.HostID
INNER JOIN Ref c
ON a.ResponseCode = c.SubType
AND c.Type = 'HTTP Status'
Many Thanks
I think it would be something like:
var result = from a in Context.DGApprovedLink
join h in Context.DGHost on a.HostID equals h.ID
join c in Context.DGConfig on a.ResponseCode equals c.SubType
where c.Type == "HTTP Status"
select new {
a.ID,
a.HostID,
h.URL,
a.SourceURL,
a.TargetURL,
c.Value,
a.ExtFlag };
Create Unit test class using MStest and copy the code
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace LinqTest.Test
{
public class Employee
{
public int EmpId { get; set; }
public string Name { get; set; }
public DateTime? DOB { get; set; }
public decimal Salary { get; set; }
public DateTime DOJ { get; set; }
public bool IsActive { get; set; }
}
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public double Price { get; set; }
}
public class BookOrder
{
public int OrderId { get; set; }
public int EmpId { get; set; }
public int BookId { get; set; }
public int Quantity { get; set; }
}
[TestClass]
public class Linqtest
{
List<Employee> Employees;
List<Book> Books;
List<BookOrder> Orders;
[TestInitialize]
public void InitializeData()
{
Employees = new List<Employee>();
Books = new List<Book>();
Orders = new List<BookOrder>();
Employees.Add(new Employee(){EmpId = 1, Name ="Test1" , DOB = new DateTime(1980,12,15),IsActive = true,Salary = 4500});
Employees.Add(new Employee() { EmpId = 11, Name = "Test2", DOB = new DateTime(1981, 12, 15), IsActive = true, Salary = 3500 });
Employees.Add(new Employee() { EmpId = 5, Name = "Test3", DOB = new DateTime(1970, 2, 15), IsActive = true, Salary = 5500 });
Employees.Add(new Employee() { EmpId = 8, Name = "Test4", DOB = new DateTime(1978, 1, 15), IsActive = true, Salary = 7500 });
Employees.Add(new Employee() { EmpId = 9, Name = "Test5", DOB = new DateTime(1972, 2, 5), IsActive = true, Salary = 2500 });
Employees.Add(new Employee() { EmpId = 10, Name = "Test6", DOB = new DateTime(1980, 10, 8), IsActive = false, Salary = 5500 });
Employees.Add(new Employee() { EmpId = 15, Name = "Test7", DOB = new DateTime(1983, 11, 25), IsActive = true, Salary = 3500 });
Books.Add(new Book(){BookId = 2, Price = 24.99,Title = "British Food"});
Books.Add(new Book() { BookId = 5, Price = 4.99, Title = "Holidays in UK" });
Books.Add(new Book() { BookId = 7, Price = 7.99, Title = "UK Laws" });
Orders.Add(new BookOrder(){EmpId = 1,OrderId = 1,BookId = 2,Quantity = 3});
Orders.Add(new BookOrder() { EmpId = 1, OrderId = 1, BookId = 5, Quantity = 1 });
Orders.Add(new BookOrder() { EmpId = 1, OrderId = 2, BookId = 7, Quantity = 5 });
Orders.Add(new BookOrder() { EmpId = 11, OrderId = 3, BookId = 2, Quantity = 3 });
Orders.Add(new BookOrder() { EmpId = 11, OrderId = 4, BookId = 7, Quantity = 3 });
}
[TestMethod]
public void CheckEmpCount()
{
var res = Employees
.Where(e => e.EmpId > 5)
.Where(t =>t.Salary>=5000);
Assert.AreEqual(2,res.Count());
res = Employees
.Where(e => e.EmpId > 5);
Assert.AreEqual(5,res.Count());
}
[TestMethod]
public void TestGroupBy()
{
var res = from e in Employees
group e by e.Salary;
Assert.AreEqual(5,res.Count());
var res1 = Employees.GroupBy(e => e.Salary);
Assert.AreEqual(5, res1.Count());
}
[TestMethod]
public void TestJoin()
{
var res = from o in Orders
join Employee e in Employees
on o.EmpId equals e.EmpId
where o.EmpId == 11
select o;
Assert.AreEqual(2,res.Count());
}
[TestMethod]
public void TestJoinData()
{
var res = from o in Orders
join Employee e in Employees
on o.EmpId equals e.EmpId
join Book b in Books
on o.BookId equals b.BookId
orderby e.EmpId
select new {o.OrderId, e.Name, b.Title, b.Price};
Assert.AreEqual("Test1", res.First().Name);
}
}
}

How to Translate SQL "WHERE expr IN (query)" into LINQ?

Basically I want to make this SQL query with linq:
SELECT *
FROM Orders
WHERE Identifier IN (SELECT DISTINCT [Order] FROM OrderRows WHERE Quantity = '1')
This is what I have come up with:
var q = from o in db.Orders
where o.Identifier in (from r in db.OrderRows
where r.Quantity == 1 select r.Order).Distinct());
But the in after o.Identifier is not valid.
What is the correct syntax for the keyword IN?
I'm a little late, but I made a demo!
As other people have stated, I always use Contains:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ContainsExample
{
class Program
{
static void Main(string[] args)
{
var foos = new List<Foo>
{
new Foo { ID = 1, FooName = "Light Side" },
new Foo { ID = 2, FooName = "Dark Side" }
};
var bars = new List<Bar>
{
new Bar { ID = 1, BarName = "Luke", FooID = 1 },
new Bar { ID = 2, BarName = "Han", FooID = 1 },
new Bar { ID = 3, BarName = "Obi-Wan", FooID = 1 },
new Bar { ID = 4, BarName = "Vader", FooID = 2 },
new Bar { ID = 5, BarName = "Palpatine", FooID = 2 },
new Bar { ID = 6, BarName = "Fett", FooID = 2 },
new Bar { ID = 7, BarName = "JarJar", FooID = 3 }
};
var criteria = from f in foos
select f.ID;
var query = from b in bars
where criteria.Contains(b.FooID)
select b;
foreach (Bar b in query)
{
Console.WriteLine(b.BarName);
}
Console.WriteLine();
Console.WriteLine("There should be no JarJar...");
Console.ReadLine();
}
}
public class Foo
{
public int ID { get; set; }
public string FooName { get; set; }
}
public class Bar
{
public int ID { get; set; }
public string BarName { get; set; }
public int FooID { get; set; }
}
}
from o in db.Orders
where o.Identifier.Any
(
from r in db.OrderRows
where r.Quantity == 1
select r.Order
).Distinct()
select o
Try this...
It seems like you want a join:
var q = (from o in db.Orders
join r in db.OrderRows on o.Identifier equals r.Order
where r.Quantity == 1
select o).Distinct();
var q = from o in db.Orders
where (from r in db.OrderRows
where r.Quantity == 1 select r.Order).Distinct().Contains(o.Identifier);
The short answer is you want to take advantage of the Contains method.
int[] ids = { 2, 5, 6, 1 };
var a = from myRecords in context.db
where ids.Contains (myRecords.id)
select new {Id = myRecords.id};
Filtering on two sets of results works the same way, in that you can filter on any common property shared by the two sets:
string[] cities = { "London", "Paris", "Seattle" };
var query = dataContext.Customers.Where (c => cities.Contains (c.City));
have you tried using something like this:
int[] inKeyword = { 5, 7, 9 };
var q = from o in db.Orders.Where(p => inKeyword.Contains(p.Identifier));
Hope it helps :)

Using Linq to select maximum value in a group

Oh, I just find that the error is caused by another part of code.
Case closed.
I have 2 tables
1- userinfo
id uid name
1 11 Billy
2 22 Paul
3 33 Joshua
2- Score
id uid score
1 11 30
2 22 40
3 11 50
4 11 60
5 33 20
6 33 70
7 33 80
I have a class called ScoreUser
public class ScoreUser{
public long uid{get; set;}
public string name{get;set;}
public int score{get;set;}
}
I want to use linq to query the above two tables, get the maximum score of each user and map it into the ScoreUser Object.
I use the following code:
from s in Scores
join i in UserInfos
on s.uid equals i.uid
group uscore by new { s.uid, i.name} into g
let maxScore = g.Max(p => p.score)
select new ScoreUser
{
uid = g.Key.uid,
name = g.Key.name,
score = maxScore
}
However, this code does does not work. It produces 7 objects instead of 3.
What should I do?
You are also grouping by score when it should be the aggregator. Try this:
from s in Scores
join i in UserInfos on s.uid equals i.uid
group by new { s.uid, i.name } into g
select new ScoreUser
{
uid = g.Key.uid
name = g.Key.name,
score = g.Max(p => p.score)
}
(update)
I see you found the problem. However I leave you here a test to this query:
class UserInfo
{
public int Id { get; set; }
public int UId { get; set; }
public string Name { get; set; }
}
class Score
{
public int Id { get; set; }
public int UId { get; set; }
public int SScore { get; set; }
}
public class ScoreUser
{
public int uid { get; set; }
public string name { get; set; }
public int score { get; set; }
public override string ToString()
{
return string.Format("UId:{0} Name:{1} Score:{2}", uid, name, score);
}
}
static void Main(string[] args)
{
List<UserInfo> infos = new List<UserInfo>()
{
new UserInfo {Id = 1, UId = 11, Name = "Billy"},
new UserInfo {Id = 2, UId = 22, Name = "Paul"},
new UserInfo {Id = 3, UId = 33, Name = "Joshua"}
};
List<Score> scores = new List<Score>()
{
new Score {Id = 1, UId = 11, SScore = 30},
new Score {Id = 2, UId = 22, SScore = 40},
new Score {Id = 3, UId = 11, SScore = 50},
new Score {Id = 4, UId = 11, SScore = 60},
new Score {Id = 5, UId = 33, SScore = 20},
new Score {Id = 6, UId = 33, SScore = 70},
new Score {Id = 7, UId = 33, SScore = 80}
};
var qry = from s in scores
join i in infos on s.UId equals i.UId
group s by new { s.UId, i.Name } into g
select new ScoreUser
{
uid = g.Key.UId,
name = g.Key.Name,
score = g.Max(p => p.SScore)
};
foreach (var su in qry)
{
Console.WriteLine(su);
}
}
Prints:
UId:11 Name:Billy Score:60
UId:22 Name:Paul Score:40
UId:33 Name:Joshua Score:80
for someone's flavor, providing here two LINQ using lambda expressions to select maximum value in a group
LINQ using lambda expressions
qry = Scores.Join(UserInfos, s => s.uid, i => i.uid, (s, i) => new { s, i })
.GroupBy(g => new { g.s.uid, g.i.name })
.Select(g => new ScoreUser
{
uid = g.Key.uid,
name = g.Key.name,
score = g.Max(p => p.s.score)
});
LINQ(Lambda) using LastOrDefault() to get Max() value, so the class ScoreUser() can be eliminated here.
var qry = Scores.Join(UserInfos, s => s.uid, i => i.uid, (s, i) => new { s, i })
.GroupBy(g => new { g.s.uid, g.i.name })
.Select(g => new { su = g.OrderBy(i => i.s.score) })
.Select(x => x.su.LastOrDefault()).ToList();
Both get same results as LINQ with query syntax.
This document may be interested
LINQ Query Syntax versus Method Syntax.
var list = records.GroupBy(p => p.Year, (key, g) => g.OrderByDescending(y => y.Month).First()).ToList();
Above query will return a list that includes the highest month item by grouping the years.

Categories