繁体   English   中英

比较清单 <T> 与对象T

[英]Compare List<T> with object T

我有一个空的名单,可以说是学生。 在将学生插入列表之前,我想检查是否已经有一个具有相同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根本没有帮助。

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 ,或者使用某些字段/属性而不是局部变量来存储学生列表,否则方法毫无意义。

发现重复项后中断循环:

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时执行添加。

根据之后需要对对象执行的操作,通常这是当HashTable是集合对象(而不是List )的最佳选择时的主要示例。 如果以后需要通过ID查找,则Dictionary集合可能是最佳选择。

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

假设您使用的是.Net 3.5或更高版本,请使用通用HashSet而不是列表,并实现自己的用于比较ID 的equals方法以及getHashcode方法。

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

另一种可能性是使用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();
    }
}

好,完全重写...

给定来自任意来源的学生数据列表-数据库,平面文件等-您可以使用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();

您可以在两个列表中的任何一个上进行其他处理,以确定谁有重复项,等等。

        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查询来执行相同的操作。

您可以使用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));
    }
}
}

词典无疑是前进的道路。 使用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
}

您可以实现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上的这篇非常好的文章

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM