I encountered a ridiculous problem using Linq into C# with my database included.
I tried so hard to sort by the name who got the higher rank of occurence.
Such as :
Toto : 1 occurence.
Titi : 3 occurences.
fonction.
consolewriteLine(the one who got the higher score of occurences )
So, it will be Titi.
But now in Linq, this is my code :
public static void AfficherLePrenomMasculinLePlusFrequentParmiLesElus()
{
using (var context = new electionEDM3())
{
var queryPrenomMasculin = from listedesprenomsM in context.Candidat
where listedesprenomsM.sexe == "M"
select listedesprenomsM;
var prenomMasculinTrouve = from prenommasculintrouve in queryPrenomMasculin
orderby prenommasculintrouve.prenom
group prenommasculintrouve by prenommasculintrouve.prenom into nombredeprenommasculintrouve
select new
{
prenom = nombredeprenommasculintrouve.Key,
count = nombredeprenommasculintrouve.Count()
};
foreach (var PrenomMPlusSouventPresent in prenomMasculinTrouve)
{
int i = 0;
int BestPrenomM = 0;
string MeilleurPrenomMasculin = "";
if ( PrenomMPlusSouventPresent.count > BestPrenomM)
{
BestPrenomM = PrenomMPlusSouventPresent.count;
MeilleurPrenomMasculin = PrenomMPlusSouventPresent.prenom;
BestPrenomM++;
}
Console.WriteLine(BestPrenomM);
}
}
}
As a result, i only got all the occurences of the " Prenom ". And not the one who got the higher score.
What should i do ?
Thank for your answers !
you are ordering using prenommasculintrouve.prenom and after that you are grouping, that is useless. You should order the result of the grouped data, using the count property of your anonymous type (prenom, count properties)
Your order by in your initial grouping is unnecessary.
Get the grouping first, then order by count descending, and take the first value. That should be the result you need.
I will give you a simple example
public class Person
{
public string Sex { get; set; }
public string name { get; set; }
}
private static void Linq2()
{
var namesList = new List<Person>();
namesList.Add(new Person() { Sex = "M", name = "Jonh" });
namesList.Add(new Person() { Sex = "M", name = "James" });
namesList.Add(new Person() { Sex = "F", name = "Maria" });
namesList.Add(new Person() { Sex = "F", name = "Cindy" });
namesList.Add(new Person() { Sex = "M", name = "Jim" });
namesList.Add(new Person() { Sex = "F", name = "Helen" });
namesList.Add(new Person() { Sex = "M", name = "Jonh" });
namesList.Add(new Person() { Sex = "F", name = "Maria" });
namesList.Add(new Person() { Sex = "F", name = "Cindy" });
namesList.Add(new Person() { Sex = "M", name = "Jonh" });
var grouped = from personItem in namesList
group personItem by personItem.name into personGroup
select new
{
name = personGroup.Key,
count = personGroup.Count()
};
// here you order your list Descending in order the name
// with the most Ocurrance will be on the top and select the First
var nameMaxOcurrance = grouped.OrderByDescending(x => x.count).First().name;
var maxOcurrance = grouped.Max(x => x.count);
Console.WriteLine("Name with Max Ocurrances:" + nameMaxOcurrance);
Console.WriteLine("Max Ocurrances:" + maxOcurrance);
}
In your case
var nameMaxOcurrance = prenomMasculinTrouve.OrderByDescending(x => x.count).First().prenom;
var maxOcurrances = prenomMasculinTrouve.Max(x => x.count);
Related
I have a Customer class with First and Last name attributes. Also, I have a list of customers.
public static List<Customer> customersList = new List<Customer>();
Given a first and last name, what's the cleanest way to find out if this name appears on the list more than once?
Define class
public class Customer
{
public string FName { get; set; }
public string LName { get; set; }
public int Count { get; set; }
}
Query here
List<Customer> list = new List<Customer>();
list.Add(new Customer() { FName = "A", LName = "L" });
list.Add(new Customer() { FName = "A", LName = "L" });
list.Add(new Customer() { FName = "B", LName = "L" });
list.Add(new Customer() { FName = "B", LName = "L" });
list.Add(new Customer() { FName = "C", LName = "L" });
var isDup = list.Where(x => x.FName.Equals("A") && x.LName.Equals("L")).Count() > 1;
var isNotDup = list.Where(x => x.FName.Equals("C") && x.LName.Equals("L")).Count() > 1;
Result
isDup is true
isNotDup is false
I have class like this
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public GRADE Grade { get; set; }
public string Nationality { get; set; }
}
public enum GRADE
{
A = 0,
B = 1,
C = 2,
D = 3,
E = 4
}
var list = new List<Student>();
list.Add(new Student() { Id = 1, Name = "Prasad", Gender = "M", Nationality = "India", Grade = GRADE.A });
list.Add(new Student() { Id = 2, Name = "Raja", Gender = "M", Nationality = "India", Grade = GRADE.B });
list.Add(new Student() { Id = 3, Name = "Hindu", Gender = "F", Nationality = "India", Grade = GRADE.A });
list.Add(new Student() { Id = 4, Name = "Hamed", Gender = "M", Nationality = "India", Grade = GRADE.C });
list.Add(new Student() { Id = 5, Name = "Priya", Gender = "F", Nationality = "India", Grade = GRADE.D });
list.Add(new Student() { Id = 6, Name = "Meera", Gender = "F", Nationality = "India", Grade = GRADE.B });
I got the solution like this, For each expression i want to write bunch of code.. Sum,Avg,Count etc
Linq Expressions
//count
var c = (from x in list.GroupBy(k => k.Gender)
select new
{
category = x.Key,
Value = x.Count()
}).ToList();
//sum
var s = (from x in list.GroupBy(k => k.Gender)
select new
{
category = x.Key,
Value = x.Sum(k => (int)k.Grade)
}).ToList();
//avg
var a = (from x in list.GroupBy(k => k.Gender)
select new
{
category = x.Key,
Value = x.Average(k => (int)k.Grade)
}).ToList();
I am trying to make one function, based on the aggregate function; it should return the value, I tried I could not find it.
One issue you have is that all three aggregates do not have the same return type, also if you use a function then the return type would have to be object because you are returning an anonymous type.
The closest I could get to what I think you want was this;
Step 1: create a new type;
public class AggregateValue<T>
{
public string Category { get; set; }
public T Value { get; set; }
}
Step 2: Create a function that returns a collection of this type and accepts a Func as a parameter that will calculate your different aggregates;
IEnumerable<AggregateValue<T>> GetAggregateValues<T>(List<Student> students, Func<IEnumerable<Student>, T> aggregateFunction)
{
return (from x in students.GroupBy(k => k.Gender)
select new AggregateValue<T>
{
Category = x.Key,
Value = aggregateFunction(x)
}).ToList();
}
You can use it like this;
var list = new List<Student>();
list.Add(new Student() { Id = 1, Name = "Prasad", Gender = "M", Nationality = "India", Grade = GRADE.A });
list.Add(new Student() { Id = 2, Name = "Raja", Gender = "M", Nationality = "India", Grade = GRADE.B });
list.Add(new Student() { Id = 3, Name = "Hindu", Gender = "F", Nationality = "India", Grade = GRADE.A });
list.Add(new Student() { Id = 4, Name = "Hamed", Gender = "M", Nationality = "India", Grade = GRADE.C });
list.Add(new Student() { Id = 5, Name = "Priya", Gender = "F", Nationality = "India", Grade = GRADE.D });
list.Add(new Student() { Id = 6, Name = "Meera", Gender = "F", Nationality = "India", Grade = GRADE.B });
var sumGrades = new Func<IEnumerable<Student>, int>(p => p.Sum(l => (int)l.Grade));
var aveGrades = new Func<IEnumerable<Student>, double>(p => p.Average(k => (int)k.Grade));
var count = new Func<IEnumerable<Student>, int>(p => p.Count());
var c = GetAggregateValues(list, count);
var s = GetAggregateValues(list, sumGrades);
var a = GetAggregateValues(list, aveGrades);
You can combine all your aggregations in one statement:
var result = (from x in list.GroupBy(k => k.Gender)
select new
{
category = x.Key,
Count = x.Count(),
Sum = x.Sum(k => (int)k.Grade),
Average = x.Average(k => (int)k.Grade)
}).ToList();
Have a collection
List<<KeyValuePair<string, Person>>
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int MealType { get; set; }
}
patientEffort.Add("1", new Person() { FirstName = "Raja", LastName = "Ram", MealType = 2 });
patientEffort.Add("2", new Person() { FirstName = "Vijay", LastName = "Anthony", MealType = 1 });
patientEffort.Add("2", new Person() { FirstName = "Vijay", LastName = "Anthony", MealType = 2 });
patientEffort.Add("2", new Person() { FirstName = "Vijay", LastName = "Anthony", MealType = 3 });
patientEffort.Add("3", new Person() { FirstName = "Dr", LastName = "APJ", MealType = 1 });
patientEffort.Add("3", new Person() { FirstName = "Dr", LastName = "APJ", MealType = 2 });
patientEffort.Add("3", new Person() { FirstName = "Dr", LastName = "APJ", MealType = 3 });
patientEffort.Add("3", new Person() { FirstName = "Dr", LastName = "APJ", MealType = 4 });
List<int> _listMealType = new List<int>();
If _listMealType= [2] passed then Result will be
{Key: "1", FirstName = "Raja", LastName = "Ram"}
{Key: "2", FirstName = "Vijay", LastName = "Anthony"}
{Key: "3", FirstName = "Dr", LastName = "APJ"}
If _listMealType= [1,2,3] passed then Result will be
{Key: 2, FirstName = "Vijay", LastName = "Anthony"}
{Key: 3, FirstName = "Dr", LastName = "APJ"}
If _listMealType= [1,2,3,4] passed then Result will be
{Key: "3", FirstName = "Dr", LastName = "APJ"} only
Key may be string or int that doesn't matter. May I have linq query for this scenario. I have used All method is linq but not worked.
var query = patientEffort.Where(d => _listMealType.All(x => x == d.Value.MealType)).Select(d => d.Key);
Could you please help me in solving the query issue as soon as possible.
I hope it helps:
var patients = patientEffort.GroupBy(x => x.Value.FirstName);
var result = (from patient in patients let res = patient.Select(note => note.Value.MealType).ToList() where _listMealType.Intersect(res).Count() == _listMealType.Count select patient.First()).ToList();
Here is variant without linq using:
var patients = patientEffort.GroupBy(x => x.Value.FirstName); // group patients by name
foreach (var patient in patients)
{
var res = new List<int>();
foreach (var note in patient) // collect all meal types of current patient
res.Add(note.Value.MealType);
if (_listMealType.Intersect(res).Count() == _listMealType.Count) // if intersection count equal to source meal list - it's our patient.
result.Add(patient.First()); // add information about patient. because we need only name - we can use first record in list.
}
I'm trying to write a program that shows duplicate records to the user to correct the data or remove the duplicate rows. It works, but I had to put a Where clause in my lambda expression to get this working. How can I remove this useless clause?
Where(d => d.Id > 0) at line 22.
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
static void Main(string[] args)
{
List<Person> dt = new List<Person>();
dt.Add(new Person() { Id = 1, Name = "MICHAEL JACKSON", Age = 50 });
dt.Add(new Person() { Id = 2, Name = "MICHAEL JACKSON", Age = 51 });
dt.Add(new Person() { Id = 3, Name = "JOHN LENNON", Age = 40 });
dt.Add(new Person() { Id = 4, Name = "JOHN LENNON", Age = 41 });
dt.Add(new Person() { Id = 5, Name = "ELVIS PRESLEY", Age = 42 });
var duplicates = dt.AsEnumerable().GroupBy(r => r.Name).Where(gr => gr.Count() > 1).ToList();
if (duplicates.Any())
{
var query = duplicates.SelectMany(c => c.Where(d => d.Id > 0)).AsQueryable();
foreach (var item in query)
Console.WriteLine(String.Format("{0} - {1}", item.Name, item.Age));
}
else
Console.WriteLine("No records duplicates.");
Console.ReadLine();
}
}
This is just sample code, my code does a lot of other checks, but if somebody knows how to remove this clause it will be very helpful to me. I think it could impact performance.
this here also works:
List<Person> dt = new List<Person>();
dt.Add(new Person() { Id = 1, Name = "MICHAEL JACKSON", Age = 50 });
dt.Add(new Person() { Id = 2, Name = "MICHAEL JACKSON", Age = 51 });
dt.Add(new Person() { Id = 3, Name = "JOHN LENNON", Age = 40 });
dt.Add(new Person() { Id = 4, Name = "JOHN LENNON", Age = 41 });
dt.Add(new Person() { Id = 5, Name = "ELVIS PRESLEY", Age = 42 });
var duplicates = dt.GroupBy(r => r.Name).Where(gr => gr.Count() > 1).ToList();
if (duplicates.Any())
{
foreach (var item in duplicates)
Console.WriteLine(String.Format("{0} - {1}", item.Key, string.Join(",", item.Select(p => p.Age))));
}
else
Console.WriteLine("No records duplicates.");
Console.ReadLine();
This works for me.
var query = duplicates.SelectMany(c => c).AsQueryable();
thats becouse duplicates is the grouped by object. try this if you only want to show the name:
var query = duplicates.Select(c => c.Key);
foreach (var item in query)
Console.WriteLine(String.Format("{0}", item));
try this if you want to show repeated ages:
var query = duplicates.SelectMany(i => i);
foreach (var item in query)
Console.WriteLine(String.Format("{0} - {1}", item.Name, item.Age));
class Customer : IEquatable<Customer>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string ZipCode { get; set; }
public bool Equals(Customer other)
{
if (ReferenceEquals(null, other)) return false;
return this.FirstName.Equals(other.FirstName) && this.LastName.Equals(other.LastName)
&& this.ZipCode.Equals(other.ZipCode);
}
public override bool Equals(object obj)
{
return this.Equals(obj as Customer);
}
public override int GetHashCode()
{
return this.FirstName.GetHashCode() ^ this.LastName.GetHashCode();
}
}
static void Main(string[] args)
{
List<Customer> allCustomers = new List<Customer>();
allCustomers.Add(new Customer { FirstName = "A", LastName = "V", ZipCode = "11111" });
allCustomers.Add(new Customer { FirstName = "B", LastName = "W", ZipCode = "11111" });
allCustomers.Add(new Customer { FirstName = "C", LastName = "X", ZipCode = "22222" });
allCustomers.Add(new Customer { FirstName = "D", LastName = "Y", ZipCode = "33333" });
allCustomers.Add(new Customer { FirstName = "E", LastName = "Z", ZipCode = "33333" });
List<Customer> subList = new List<Customer>();
subList.Add(new Customer { FirstName = "A", LastName = "V", ZipCode = "11111" });
subList.Add(new Customer { FirstName = "B", LastName = "W", ZipCode = "11111" });
subList.Add(new Customer { FirstName = "C", LastName = "X", ZipCode = "22222" });
//This gives expected answer
var n = subList.Except(allCustomers).ToList();
//This should compare only for those customers who zip matches with Sublist's zip
//This returns customers with zip code "33333" while it should not
var v = allCustomers.Except(subList).ToList();
}
var V is not supposed to return customer with zipcode "33333". How do i compare so that it ignores those Customers whose Zip is not present in the Sublist?
var zipCodes = subList.Select( c=> c.ZipCode).Distinct().ToList();
var v = allCustomers.Where( c=> zipCodes.Contains(c.ZipCode) )
.Except(subList)
.ToList();
Why are you saying V should not include zipcode 33333? allCustomers - subList would remove the common elements but keep the unique elements of allCustomers.
It's a set difference, so {A, B, C, D, E} - {A, B, C} = {D, E} thus the 33333 should show...
Seems similar to this example from MSDN: http://msdn.microsoft.com/en-us/library/bb300779.aspx