将List <t>与对象T </t>进行比较

时间:2014-05-07 23:16:23

标签: c# comparison

我有一个空列表,让我们说学生。在我在列表中插入学生之前,我想检查是否已经有一个具有相同ID的学生。

请注意,这是伪代码!

class Student
{
    public int ID { get; set; } // ID is NOT unique
    public string Name { get; set; }
    public int Age { get; set; }

    public List<Student> AddStudentsToList()
    {
        List<Student> students = new List<Student>();

        foreach (Student student in source) // source is the place where the information comes from(text file, DB, etc.)
        {
            if (CompareStudents(students, student)) // Here's the place where I have to check if student with the current ID already exists in the list students(List<Student>)
            {
                students.Add(new Student(student));
            }
        }
        return students;
    }

    private bool CompareStudents(List<Student> students, Student s) // Going through the whole list every time can't be the best solution, I think
    {
        bool duplicate = false;
        foreach (var student in students)
        {
            if (student.ID == s.ID)
            {
                duplicate = true;
            }
        }

        return duplicate;
    }
}

我可以(以及如何)更有效地做到这一点吗?

注意:我需要跟踪重复项,因此Dictionary根本没有帮助。

10 个答案:

答案 0 :(得分:2)

public void AddStudentsToList()
{
    List<Student> students = new List<Student>();
    HashSet<int> ids = new HashSet<int>();

    foreach (Student student in source)
    {
        if (!ids.Add(student.ID))
        {
            students.Add(new Student(student));
        }
    }
}

顺便说一句,您可能希望从您的方法返回students或使用某个字段/属性而不是局部变量来存储学生列表,否则方法毫无意义。

答案 1 :(得分:0)

找到副本后打破循环:

foreach (var student in students)
{
     if (student.ID == s.ID)
     {
         duplicate = true;
         break;
     }
}

您可以使用Enumerable.Any方法执行相同的操作:

return students.Any(student => student.ID == s.ID);

如果您想要更有效的解决方案,可以使用HashSet

return new HashSet<Student>(students).Count == students.Count;

这还需要覆盖您的课程的EqualsGetHashCode方法,如下所示:

class Student
{
    public int ID { get; set; } 
    public string Name { get; set; }
    public int Age { get; set; }

    public override bool Equals(object obj)
    {
        return this.ID.Equals(((Student)obj).ID);
    }

    public override int GetHashCode()
    {
        return this.ID.GetHashCode();
    }
}

另外,不要忘记将if语句更改为:

if (!CompareStudents(students, student))

如果存在重复,您的方法将返回 true ,因此您需要使用否定运算符,因为您只想在CompareStudents返回 false 时执行添加。 / p>

答案 2 :(得分:0)

根据之后对象需要做的事情,这通常是HashTable是集合对象的最佳选择时的一个主要示例 - 而不是List。如果您以后需要按ID进行查找,那么Dictionary集合可能是最佳选择。

知道何时选择正确的集合可以使您的代码更容易。更多信息:http://geekswithblogs.net/BlackRabbitCoder/archive/2011/06/16/c.net-fundamentals-choosing-the-right-collection-class.aspx

答案 3 :(得分:0)

假设您使用的是.Net 3.5或更高版本,请使用generic HashSet代替列表,使用implement your own equals method来比较ID以及getHashcode方法。

如果元素已经存在,HashSet上的add方法将返回false。

答案 4 :(得分:0)

另一种可能性是使用Distinct,但前提是您实施IEqualityComparer<Student>或使Student具有可比性:

class Student
{
    public int ID { get; set; } // ID is NOT unique
    public string Name { get; set; }
    public int Age { get; set; }

    public List<Student> AddStudentsToList()
    {
        var students = source.Distinct().ToList();

        return students;
    }

    public override bool Equals(Student other)
    {
        var otherStudent = other as Student;

        if (otherStudent == null)
        {
            return false;
        }

        return otherStudent.ID == this.ID;
    }

    public override int GetHashCode()
    {
        return this.ID.GetHashCode();
    }
}

答案 5 :(得分:0)

好的,完全重写......

给出来自任意来源的学生数据列表 - 数据库,平面文件等 - 您可以使用LINQ查询或扩展以多种有趣的方式重新排列列表。

例如:

public class LoadedStudent
{
    public int ID;
    public Student Primary;
    public Student[] Duplicates;
}

public List<LoadedStudent> LoadStudents(IEnumerable<Student> source)
{
    var query = 
        from s in students
        group s by s.ID into grp
        let primary = grp.First()
        select new LoadedStudent 
        { 
            ID = primary.ID,
            Primary = primary,
            Duplicates = grp.Skip(1).ToArray()
        };

    return Query.ToList();
}

从上面你可以得到一个由ID组合在一起的所有已加载学生的列表,其中一个被选为主要,其余被放入一个数组。将导入列表转换为List<Student>非常简单:

List<LoadedStudent> loadedstudents = LoadStudents(source);
List<Student> students = loadedstudents.Select(ls => ls.Primary).ToList();

您可以对其中一个列表执行其他处理,以确定谁有重复项等。

答案 6 :(得分:0)

        List<Student> lstNumbers = new List<Student>();
        Student studentInstance = new Student();
        studentInstance.ID=1;
        studentInstance.Name="Student1";
        studentInstance.Age = 55;
        Student testStudent = lstNumbers.Find(p => p.ID == studentInstance.ID);
        if (testStudent == null)
        {
            lstNumbers.Add(studentInstance);
        }   

您可以使用上述代码之类的扩展方法,也可以使用LINQ查询来执行相同的操作。

答案 7 :(得分:0)

您可以使用Linq缩短代码购买支票ID,删除!在if()语句中,如果您只想将重复的学生添加到列表中。但由于你的名单最初是空的,你不会在那里添加任何学生,因为你找不到任何重复的学生。

public void AddStudentsToList()
{
List<Student> students = new List<Student>();

foreach (Student student in source)
{
    if (!students.where(s => s.ID == student.ID).any())
    {
        students.Add(new Student(student));
    }
}
}

答案 8 :(得分:0)

词典绝对是前进的方向。使用ContainsKey确定您是否已拥有特定ID。如果没有,则将新的添加到字典中。如果您这样做,则将其存储在重复列表中。

class Student
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}
Dictionary<int, Student> students = new Dictionary<int, Student>();
List<Student> duplicates = new List<Student>();
private void ReadStudents(IEnumerable<Student> source)
{
    // source could contain the same student more than once
    foreach (Student student in source)
    {
        if (students.ContainsKey(student.ID))
            duplicates.Add(student);
        else
            students[student.ID] = student;
    }
}
public void Test()
{
    List<Student> input = new List<Student>() { 
        new Student { ID=1, Name="Adam", Age=18 },
        new Student { ID=2, Name="Bert", Age=18 },
        new Student { ID=3, Name="Charlie", Age=19 },
        new Student { ID=1, Name="Adam", Age=18 }, // duplicate
    };

    ReadStudents(input);
    // 'students' now contains the list with duplicates removed
    // 'duplicates' contains all the duplicates
}

答案 9 :(得分:0)

您可以实现IEqualityComparer

class Equalitycompare<T> : IEqualityComparer<T>
{
    Func<T, T, bool> _equalsFunction;
    Func<T, int> _hashCodeFunction;

    public Equalitycompare( Func<T, T, bool> equalsFunction, Func<T, int> hashCodeFunction)
    {
        if (equalsFunction == null) throw new ArgumentNullException();
        if (hashCodeFunction == null) throw new ArgumentNullException();

     _equalsFunction = equalsFunction;
     _hashCodeFunction = hashCodeFunction;
    }
    public bool Equals(T x, T y)
    {
        return _equalsFunction(x, y);
    }

    public int GetHashCode(T obj)
    {
        return _hashCodeFunction(obj);
    }
}

 static void Main(string[] args)
 {
    Student Student1 = new Student();
    Student1.ID = 1;
    Student Student2 = new Student();
    Student2.ID = 1;
    Student Student3 = new Student();
    Student3.ID = 3;
    var comparer = new Equalitycompare<Student>((x, y) => x.ID == y.ID, x =>           x.ID.GetHashCode());
   var students = new List<Student>{Student1,Student2,Student3};
   var uniquestudents = students.Distinct(comparer);
 }

http://www.blackwasp.co.uk/LambdaEqualityComparer.aspx

上查看这篇非常好的文章