Home > database >  Get distinct strings from a list then create a new object and add it to the same list
Get distinct strings from a list then create a new object and add it to the same list

Time:10-29

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);
  •  Tags:  
  • c#
  • Related