i am trying to write a linq that will return the id of the employee who has the most entries in the table.
This is how my class looks like
public class TrainingEmployee
{
public int EmployeeId { get; set; }
public int TrainingId { get; set; }
public List<TrainingEmployee> GenerateData()
{
return new List<TrainingEmployee>()
{
new TrainingEmployee() { EmployeeId = 1, TrainingId = 2},
new TrainingEmployee() { EmployeeId = 1, TrainingId = 2},
new TrainingEmployee() { EmployeeId = 1, TrainingId = 2},
new TrainingEmployee() { EmployeeId = 1, TrainingId = 2},
new TrainingEmployee() { EmployeeId = 2, TrainingId = 3},
new TrainingEmployee() { EmployeeId = 2, TrainingId = 3},
new TrainingEmployee() { EmployeeId = 2, TrainingId = 3},
new TrainingEmployee() { EmployeeId = 2, TrainingId = 3},
new TrainingEmployee() { EmployeeId = 2, TrainingId = 5},
new TrainingEmployee() { EmployeeId = 2, TrainingId = 5},
new TrainingEmployee() { EmployeeId = 2, TrainingId = 1},
};
}
}
And this is how my code looks so far
var lista = new TrainingEmployee();
var data = lista.GenerateData().GroupBy(x => x.EmployeeId);
var maxValue = 0;
var employeeId = 0;
foreach (var group in data)
{
var currentlyGroupCount = group.Count();
if(currentlyGroupCount > maxValue)
{
maxValue = currentlyGroupCount;
employeeId = group.Key;
}
}
Console.WriteLine("Value: {0} employeeid: {1}", maxValue, employeeId);
How can i do the above code in just a linq without using that much of a code?
You could order it descending and select the first one:
var employee = GenerateData()
// group on EmployeeId
.GroupBy(e => e.EmployeeId)
// reverse order it on count
.OrderByDescending(g => g.Count())
// select the first
.FirstOrDefault();
// check if the query returned anything other than default.
if(employee != default)
Console.WriteLine("Value: {0} employeeid: {1}", employee.Count(), employee.EmployeeId);
Another approach similar to jeroen-van-langen's answer but using MoreLINQ's MaxBy():
GenerateData()
.GroupBy(e => e.EmployeeId)
.MaxBy(e => e.Count());
This would also return multiple IDs if multiple employee's had the same "max count"; a possibility in your scenario.
This evaluates Count() once for each employees group so is a little more performant, it allows also to get both of employyId and the max count
var mostFrequentEmployeeId = GenerateData()
.GroupBy(x => x.EmployeeId, (employeeId, employeesGroup) => new { employeeId, count = employeesGroup.Count() })
.OrderByDescending(x => x.count)
.FirstOrDefault()?
.employeeId;
Related
Need to create a new list for the below list.
if UniqueID= "10345" then i need to create new record like this { rowno = 3, sid = 12, snmae = Mark ,isDataFromProfile = 1} means that need to use ProfileName, ProfileID , ProfileAge
Output based on below
My expected output is
{ rowno = 1, sid = 1000, snmae = John }
{ rowno = 2, sid = 3090, snmae = Steve }
{ rowno = 3, sid = 5090, snmae = Ron }
{ rowno = 4, sid = 4300, snmae = Bill }
{ rowno = 5, sid = 5640, snmae = Ram }
{ rowno = 6, sid = 90, snmae = Gony }
{ rowno = 3, sid = 12, snmae = Mark ,isDataFromProfile = 1}
{ rowno = 6, sid = 1987, snmae = Antony ,isDataFromProfile = 1}
class:
public class Student{
public string UniqueID{ get; set; }
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
public int StandardID { get; set; }
public string ProfileName{ get; set; }
public string ProfileID{ get; set; }
public string ProfileAge{ get; set; }
}
int counter = 1;
var sdata = studentList.Select(i => new {rowno = counter++, sid = i.StudentID, snmae = i.StudentName }).ToList();
I think this is what you are looking for?
Select has an overload that handles indexes.
var sdata = studentList.Select((Value, Index) => new { Value, Index })
.Select(x => new { rowno = x.Index, sid = x.Value.StudentID, snmae = x.Value.StudentName, isDataFromProfile = x.Value.UniqueID == "10345" ? 1 : 0 })
.ToList();
Edited answer
var sdata = studentList.Select((Value, Index) => new { Value, Index })
.Select(x => new { rowno = x.Index, sid = x.Value.StudentID, snmae = x.Value.StudentName, isDataFromProfile = 0 })
.ToList();
var otherData = studentList.Select((Value, Index) => new { Value, Index })
.Where(x => x.Value.UniqueID == "10345")
.Select(x => new { rowno = x.Index, sid = Convert.ToInt32(x.Value.ProfileID), snmae = x.Value.ProfileName, isDataFromProfile = 1 })
.ToList();
sdata.AddRange(otherData);
I have a object list like this:
using System;
using System.Collections.Generic;
using System.Linq;
public class Item
{
public int Id;
public int Price;
}
public class Program
{
public static void Main()
{
List<Item> food = new List<Item> {
new Item { Id = 1, Price = 1},
new Item { Id = 2, Price = 3},
new Item { Id = 4, Price = 9}
};
List<Item> drinks = new List<Item> {
new Item { Id = 1, Price = 1},
new Item { Id = 2, Price = 2},
new Item { Id = 3, Price = 0},
new Item { Id = 4, Price = 1},
new Item { Id = 6, Price = 1}
};
List<Item> magazines = new List<Item> {
new Item { Id = 3, Price = 1},
new Item { Id = 5, Price = 2},
};
var combined = food.Union(drinks).Union(magazines).Distinct().ToList();
}
}
What I want to do is, add all the prices into one list. Without any duplicates (Id). My goal is to have the total sum of the prices. So basically add all prices for the same ID together.
So the combined list should look like this:
List<Item> combined = new List<Item> {
new Item { Id = 1, Price = 2},
new Item { Id = 2, Price = 5},
new Item { Id = 3, Price = 1},
new Item { Id = 4, Price = 10},
new Item { Id = 5, Price = 2},
new Item { Id = 6, Price = 1}
};
Preferably using LINQ.
If you need to get a sum of prices for concatenated List<Item>, you should use GroupBy method to group the items by Id and then Sum of prices for every group
var combined = food.Concat(drinks).Concat(magazines)
.GroupBy(i => i.Id, i => i.Price, (i, prices) => new Item { Id = i, Price = prices.Sum() })
.OrderBy(i => i.Id).ToList();
You can also add OrderBy to sort the results by Id property, if it's important
var x =
// First, combine all lists
food.Concat(drinks).Concat(magazines)
// Group combined Items by Id
.GroupBy(item => item.Id)
// From all groups create final Items with Id and summed Price
.Select(g => new Item { Id = g.Key, Price = g.Sum(item => item.Price) });
I just want to check if there is quicker way using LINQ to have list removed from duplicates by id, but in result list item will have sum of some other property (in this case Price). For example:
Start list:
List<Item> a = new List<Item>
{
new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 100},
new Item {Id = 2, Name = "Item2", Code = "IT00002", Price = 200},
new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 150},
new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 100},
new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 150},
new Item {Id = 3, Name = "Item3", Code = "IT00004", Price = 250}
};
And result list would be:
List<Item> a = new List<Item>
{
new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 200},
new Item {Id = 2, Name = "Item2", Code = "IT00002", Price = 200},
new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 550}
};
In (functional) LINQ it is something like:
List<Item> b = a
.GroupBy(x => x.Id)
.Select(x => new Item { Id = x.Key, Name = x.First().Name, Code = x.First().Code, Price = x.Sum(y => y.Price) })
.ToList();
In keyword-based LINQ it is something like:
List<Item> c = (from x in a
group x by x.Id into y
select new Item { Id = y.Key, Name = y.First().Name, Code = y.First().Code, Price = y.Sum(z => z.Price) }
).ToList();
var filteredList = a.GroupBy(e => e.Id).Select(g =>
{
var item = g.First();
return new Item
{
Id = item.Id,
Name = item.Name,
Code = item.Code,
Price = g.Sum(e => e.Price)
};
}).ToList();
Something like this will do..
var result = a.GroupBy(it => new { it.Id, it.Name, it.Code })
.Select(x => new { x.Key.Id,x.Key.Name,x.Key.Code,Price = x.Sum(y=>y.Price)});
public class Item : IEquatable<Item>
{
public int? Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public int? Price { get; set; }
public bool Equals(Item Other)
{
//Check whether the compared object is null.
if (Object.ReferenceEquals(Other, null)) return false;
//Check whether the compared object references the same data.
if (Object.ReferenceEquals(this, Other)) return true;
//Check whether the products' properties are equal.
return this.Id == Other.Id;
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
}
List<Item> a = new List<Item>
{
new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 100},
new Item {Id = 2, Name = "Item2", Code = "IT00002", Price = 200},
new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 150},
new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 100},
new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 150},
new Item {Id = 3, Name = "Item3", Code = "IT00004", Price = 250}
};
var b = a.Distinct().ToList();
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;}
}
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.