2009-03-06 13 views
7

przy użyciu C# 3 i .NET Framework 3.5, mam obiekt Personznaleźć duplikaty danych obiektu w Lista obiektów

public Person 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public int SSN { get; set; } 
} 

i mam ich wykaz:

List<Person> persons = GetPersons(); 

Jak czy mogę uzyskać wszystkie obiekty Person w osobach, w których SSN nie jest unikalny na liście i usunąć je z listy osób i idealnie dodać je do innej listy o nazwie "List<Person> dupes"?

Oryginalny lista może wyglądać tak:

persons = new List<Person>(); 
persons.Add(new Person { Id = 1, 
         FirstName = "Chris", 
         LastName="Columbus", 
         SSN=111223333 }); // Is a dupe 
persons.Add(new Person { Id = 1, 
         FirstName = "E.E.", 
         LastName="Cummings", 
         SSN=987654321 }); 
persons.Add(new Person { Id = 1, 
         FirstName = "John", 
         LastName="Steinbeck", 
         SSN=111223333 }); // Is a dupe 
persons.Add(new Person { Id = 1, 
         FirstName = "Yogi", 
         LastName="Berra", 
         SSN=123456789 }); 

A wynik końcowy miałby Cummings i Berra w wykazie osób i oryginalne miałoby Columbus i Steinbeck w wykazie o nazwie duplikaty.

Wielkie dzięki!

Odpowiedz

19

To dostaje wam kopiowane SSN:

var duplicatedSSN = 
    from p in persons 
    group p by p.SSN into g 
    where g.Count() > 1 
    select g.Key; 

zduplikowana lista będzie wyglądać tak:

var duplicated = persons.FindAll(p => duplicatedSSN.Contains(p.SSN)); 

A następnie po prostu powtórz duplikaty i usuń je.

duplicated.ForEach(dup => persons.Remove(dup)); 
+1

Twoje rozwiązanie było blisko. Wiersz 'duplicated = persons.FindAll (duplikatSSN.Contains (p => p.SSN);' nie działał.Zobacz moją odpowiedź, aby zobaczyć, co poprawiłem, aby uzyskać odpowiedź. –

0

dobrze jeśli wdrożenia IComparable tak:

int IComparable<Person>.CompareTo(Person person) 
{ 
    return this.SSN.CompareTo(person.SSN); 
} 

następnie porównanie jak poniżej będzie działać:

for (Int32 i = 0; i < people.Count; i++) 
{ 
    for (Int32 j = 1; j < items.Count; j++) 
    { 
     if (i != j && items[i] == items[j]) 
     { 
      // duplicate 
     } 
    } 
} 
0

Przechodzenie przez tę listę i utrzymywanie par Hashtable of SSN/count. Następnie wyliczyć swój stolik i usunąć elementy, które pasują SSNs gdzie liczą SSN> 0.

Dictionary<string, int> ssnTable = new Dictionary<string, int>(); 

foreach (Person person in persons) 
{ 
    try 
    { 
     int count = ssnTable[person.SSN]; 
     count++; 
     ssnTable[person.SSN] = count; 
    } 
    catch(Exception ex) 
    { 
     ssnTable.Add(person.SSN, 1); 
    } 
} 

// traverse ssnTable here and remove items where value of entry (item count) > 1 
1
List<Person> actualPersons = persons.Distinct().ToList(); 
List<Person> duplicatePersons = persons.Except(actualPersons).ToList(); 
+1

To nie działało, ponieważ Distinct wygląda na wszystkich danych Chcę tylko porównać SSN i ​​szukać duplikatów na tym jednym polu –

2

Dzięki gcores za wprowadzenie mnie ruszył poprawną ścieżkę. Oto, co skończyło się robi:

var duplicatedSSN = 
    from p in persons 
    group p by p.SSN into g 
    where g.Count() > 1 
    select g.Key; 

var duplicates = new List<Person>(); 

foreach (var dupeSSN in duplicatedSSN) 
{ 
    foreach (var person in persons.FindAll(p => p.SSN == dupeSSN)) 
     duplicates.Add(person); 
} 

duplicates.ForEach(dup => persons.Remove(dup)); 
+1

Niestety, linia była błędna.Powinno powiedzieć, że duplicated = persons.FindAll (p => duplicatedSSN.Contains (p.SSN)); Zmieniłem odpowiedź. – gcores

0

Czy persons trzeba być List<Person>? Co jeśli byłby to Dictionary<int, Person>?

var persons = new Dictionary<int, Person>(); 

... 

// For each person you want to add to the list: 
var person = new Person 
{ 
    ... 
}; 

if (!persons.ContainsKey(person.SSN)) 
{ 
    persons.Add(person.SSN, person); 
} 

// If you absolutely, positively got to have a List: 
using System.Linq; 
List<Person> personsList = persons.Values.ToList(); 

Jeśli pracujemy z wyjątkowymi przypadkami Person (w przeciwieństwie do różnych instancji, że może zdarzyć się mieć takie same właściwości), można uzyskać lepszą wydajność z HashSet.

0

Na podstawie rekomendacji przez @grki powyżej.

Jeśli chcesz dodać pojedynczy przedmiot powielanego SSN powrót do listy osób, a następnie dodać następujący wiersz:

IEnumerable<IGrouping<string, Person>> query = duplicated.GroupBy(d => d.SSN, d => d); 

     foreach (IGrouping<string, Person> duplicateGroup in query) 
     { 
      persons.Add(duplicateGroup .First()); 
     } 

Moim założeniem jest to, że może chcesz tylko usunąć zduplikowane wartości minus oryginalna wartość, z której pochodzą duplikaty.

Powiązane problemy