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));
Related
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);
I want to remove items from a list of entities, when there is a concidence from a list (id). I have written this code, but I am guessing there is a better way to do it, and improve performance.
Here is my code:
List<int> toRemove; //includes the ids of the entities to be removed
if (people.Count > 1)
people.RemoveAll(x => people.Any(y => y != x && toRemove.Contains(x.ID)));
else
people.RemoveAll(x => toRemove.Contains(x.ID));
Given a list of people, for example:
var people = new List<Person>
{
new Person { ID = 1, Name = "Fred1" },
new Person { ID = 2, Name = "Fred2" },
new Person { ID = 3, Name = "Fred3" },
new Person { ID = 4, Name = "Fred4" },
new Person { ID = 5, Name = "Fred5" },
new Person { ID = 6, Name = "Fred6" },
new Person { ID = 7, Name = "Fred7" },
new Person { ID = 8, Name = "Fred8" },
new Person { ID = 9, Name = "Fred9" },
new Person { ID = 10, Name = "Fred10" }
};
And a list of IDs to remove:
List<int> toRemove = new List<int> { 3, 4, 5 };
You can remove the unwanted entries like this:
people = people.Where(p => !toRemove.Contains(p.ID)).ToList();
Oh, and for completeness, here's a Person class to complete the example!
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
}
And to show it working:
https://ideone.com/ERP3rk
How can I find the frequencies of the Age property for the List<Person>?
var people = new List<Person>
{
new Person {Name = "Jonh", Age = 10},
new Person {Name = "Jack", Age = 12},
new Person {Name = "Sara", Age = 10},
new Person {Name = "Dave", Age = 10},
new Person {Name = "Jude", Age = 12}
};
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public int Frequency { get; set; }
}
So I want my Person objects to be updated to have the Frequency value.
Name Age Frequency
----------------------------------------------
Jonh 10 3
Jack 12 2
Sara 10 3
Dave 10 3
Jude 12 2
var countByAge = people.GroupBy(x => x.Age)
.ToDictionary(g => g.Key, g => g.Count());
foreach(var person in people)
{
person.Frequency = countByAge[person.Age];
}
try like this:
foreach(var item in people)
{
item.Frequency = people.Count(x=>x.Age == item.Age);
}
How to print out all the persons and their pets, using Linq. I only want to print out persons who have pets.
Prefer result be like:
Kate Bed:
Rex
Sally
My not working solution is here:
class Program
{
static void Main(string[] args)
{
result();
}
static void result() {
var list = StaticGenator.getPersons().Where(x => x.Pets != null);
foreach (var person in list)
{
Console.WriteLine(person.Firstname + " " + person.Lastname + ":");
foreach(var pet in list){
Console.WriteLine(" " + pet.Pets);
}
}
}
What i get is:
Kate Bed:
system.collection.generic.list'1[MainLibrary.Pet]
system.collection.generic.list'1[MainLibrary.Pet]
Here is the code to understand what I am asking:
Data is held here:
public static class StaticGenator
{
public static List<Person> getPersons()
{
List<Person> persons = new List<Person>();
persons.Add(new Person() { Firstname = "Sam", Lastname = "Car", BirthDate = new DateTime(2001, 01, 01), PersonId = 1, Sex = Sex.Man });
persons.Add(new Person() { Firstname = "Kate", Lastname = "Bed", BirthDate = new DateTime(1995, 11, 11), PersonId = 2, Sex = Sex.Woman, Pets = new List<Pet>() { new Pet { Firstname = "Rex", BirthDate = new DateTime(2007, 1, 1), Sex = Sex.Man, PetId = 1 }, new Pet { Firstname = "Sally", BirthDate = new DateTime(2004, 2, 1), Sex = Sex.Woman, PetId = 2 } } });
return persons;
}
}
Person Class:
public class Person
{
public int PersonId { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public DateTime BirthDate { get; set; }
public Sex Sex{ get; set; }
public int Age {
get
{
var age= DateTime.Now.Year - BirthDate.Year;
if (DateTime.Now.Day >= BirthDate.Day && DateTime.Now.Month >= BirthDate.Month)
return age;
else
return age- 1;
}
}
public List<Pet> Pets { get; set; }
}
Pet Class:
public class Pet
{
public int PetId { get; set; }
public String Firstname { get; set; }
public Sex Sex { get; set; }
public DateTime BirthDate { get; set; }
public int Age { get; set; }
}
Sex enum:
public enum Sex{
Man,
Woman
}
foreach (var person in list)
{
Console.WriteLine(person.Firstname + " " + person.Lastname + ":");
foreach(var pet in person.Pets) // iterate over Pets of person
{
Console.WriteLine(" " + pet.Firstname); // write pet's name
}
}
Keep in mind - you can have problem if somebody will add null pet to pets collection or if there is empty pets list. So, probably correct query to get persons with pets is:
var peopleWithPets = from p in StaticGenator.getPersons()
where p.Pets != null &&
p.Pets.Any() &&
p.Pets.All(x => x != null)
select p;
Also use string formatting:
foreach (var person in peopleWithPets)
{
Console.WriteLine("{0} {1}:", person.Firstname, person.Lastname);
foreach(var pet in person.Pets)
Console.WriteLine("\t{0}", pet.Firstname);
}
Also I suggest you to follow Capitalization Styles recommended by MicroSoft.
foreach(var pet in list)
{
Console.WriteLine(" " + pet.Pets);
}
Should be:
foreach(var pet in person.Pets)
{
Console.WriteLine(" " + pet.FirstName);
}
You have to iterate over the pet collection of the current user that is being iterated.
Suppose you have some list (you mentioned above) with your datastructure
List<Person> persons = new List<Person>();
persons.Add(new Person() { Firstname = "Sam", Lastname = "Car", BirthDate = new DateTime(2001, 01, 01), PersonId = 1, Sex = Sex.Man });
persons.Add(new Person() { Firstname = "Kate", Lastname = "Bed", BirthDate = new DateTime(1995, 11, 11), PersonId = 2, Sex = Sex.Woman, Pets = new List<Pet>() { new Pet { Firstname = "Rex", BirthDate = new DateTime(2007, 1, 1), Sex = Sex.Man, PetId = 1 }, new Pet { Firstname = "Sally", BirthDate = new DateTime(2004, 2, 1), Sex = Sex.Woman, PetId = 2 } } });
You can very easily filter as well as write to console with these 4 lines of code
persons.Where(p => p.Pets != null && p.Pets.Any()).ToList().ForEach(p =>
{
Console.WriteLine(p.Firstname + " " + p.Lastname + "\n");
p.Pets.ForEach(pt => Console.WriteLine(pt.Firstname));
});
var output = String.Join("\n", persons.Select(person => $"{person.Firstname} {person.Lastname}"));
Output:
Sam Car
Kate Bed
I have a problem which I've simplified down and have been scratching my head at. If I have a list of students and I want to use LINQ to produce a group of students by Age, Grade, and LastName so I can traverse them with a nested foreach loop how would I go about this. Here is some code:
class Student
{
public int Grade;
public int Age;
public string LastName;
}
public void SomeMethod()
{
Student student1 = new Student() { Age = 10, Grade = 100, LastName = "Smith"};
Student student2 = new Student() { Age = 10, Grade = 90, LastName = "Jones" };
Student student3 = new Student() { Age = 10, Grade = 50, LastName = "Bob" };
Student student4 = new Student() { Age = 10, Grade = 100, LastName = "Smith" };
Student student5 = new Student() { Age = 11, Grade = 10, LastName = "Bob" };
Student student6 = new Student() { Age = 11, Grade = 30, LastName = "Jones" };
Student student7 = new Student() { Age = 13, Grade = 90, LastName = "Bob" };
Student student8 = new Student() { Age = 13, Grade = 90, LastName = "Smithy" };
Student student9 = new Student() { Age = 15, Grade = 100, LastName = "Smith" };
Student student10 = new Student() { Age = 15, Grade = 0, LastName = "Smith" };
List<Student> studentList = new List<Student>()
{
student1,student2,student3,student4,student5,student6,student7,student8,student9,student10
};
var studentGroups = from student in studentList
group student by student.Age into studentAgeGroup
from studentAgeGradeGroup in
(
from student in studentAgeGroup
group student by student.Grade
)
group studentAgeGradeGroup by studentAgeGroup.Key;
foreach (var ageGroup in studentGroups)
{
foreach (var gradeGroup in ageGroup)
{
foreach (var innerGroupElement in gradeGroup)
{
// At this point they are grouped by age and grade but I would also like them to be grouped by LastName
}
}
}
}
How about?
var studentGroups = from student in studentList
group student by new {student.Age, student.Grade, student.LastName};
and looping through each element in studentGroups, you can access Age by sg.Key.Age and so on.
so I can traverse them with a nested foreach loop how would I go about this.
Like this:
var studentGroups =
from student in studentList
group student by new {student.Age, student.Grade, student.LastName} into g2
group g2 by new {g2.Key.Age, g2.Key.Grade} into g1
group g1 by g1.Key.Age
foreach(var group0 in studentGroups)
{
int age = group0.Key;
foreach(var group1 in group0)
{
int grade = group1.Key.Grade
foreach(var group2 in group1)
{
string lastName = group2.Key.LastName
foreach(Student s in group2)
{
//...
}
}
}
}
Why not group them straight away?
var studentGroups = from student in studentList
group student by new { student.Age, student.Grade, student.LastName }
into studentAgeGroup
select studentAgeGroup;