I am trying to find the distinct names of a List<Person>
based on the Name
property. For each distinct name, I want to create a new object with same name property and all other properties are null. How do I do it efficiently?
Person Class.
public class Person
{
public string Name { get; set; }
public string Country { get; set; }
}
Program.cs
List<Person> personList = new List<Person>();
var p1 = new Person()
{
Name = "John",
Country = "USA"
};
var p2 = new Person()
{
Name = "John",
Country = "China"
};
var p3 = new Person()
{
Name = "Bob",
Country = "Italy"
};
var p4 = new Person()
{
Name = "Bob",
Country = "Brazil"
};
var p5 = new Person()
{
Name = "Bob",
Country = "Canada"
};
personList.Add(p1);
personList.Add(p2);
personList.Add(p3);
personList.Add(p4);
personList.Add(p5);
The aim is to add one more "John" and one more "Bob" to the same list (because they have distinct names) with country properties as the null string.
CodePudding user response:
Using a Linq query will make fairly easy work of finding all the distinct Name
values:
// first use .GroupBy to group everything by the Name property
// and then select a new Person for each grouping of Name
Person[] unique = personList.GroupBy(x => x.Name)
.Select(x => new Person{Name = x.Key})
.ToArray();
Once the new collection is created; add them to the existing collection:
personList.AddRange(unique);
Edit for use with .Disinct
Alternatively, you can get the distinct name values from the Linq .Distinct()
method, instead of using the .GroupBy()
method, but you need to select the .Name
property to get an OOB distinct comparer:
Person[] unique = personList.Select(x => x.Name)
.Distinct()
.Select(x => new Person{Name = x})
.ToArray();
personList.AddRange(unique);
Using the Distinct requires either using a built in IEqualityComparer
, or providing a custom IEqualityComparer
in the overload. Simply passing in the object itself is not valid, unless the object implements IEqualityComparer
. In this case, it's easier to either select the Name
property and call .Distinct
which will use the built-in IEqualityComparer
, or use the .GroupBy
method as in the first example.
CodePudding user response:
Use linq's Distinct method (https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinct?view=net-5.0):
public class Person
{
public string Name { get; set; }
public string Country { get; set; }
}
// Program.cs
List<Person> personList = new List<Person> ();
var p1 = new Person ()
{
Name = "John",
Country = "USA"
};
var p2 = new Person ()
{
Name = "John",
Country = "China"
};
var p3 = new Person ()
{
Name = "Bob",
Country = "Italy"
};
var p4 = new Person ()
{
Name = "Bob",
Country = "Brazil"
};
var p5 = new Person ()
{
Name = "Bob",
Country = "Canada"
};
personList.Add(p1);
personList.Add (p2);
personList.Add (p3);
personList.Add (p4);
personList.Add (p5);
var personsWithDistinctNameInPersonList = personList.Select(p => p.Name).Distinct()
.Select(n => new Person {
Name = n,
}).ToList();
personList.AddRange(personsWithDistinctNameInPersonList);