C#从包含列表的列表中删除重复项
假设我们有一份“a学生”名单和一份“B学生”名单。然后,我们将这两个列表添加到一个更通用的列表中,称为“学生”。然后,有人决定在普通的“学生”列表中添加一个重复的“a学生”列表,从而使我们的生活复杂化。删除“A学生”重复列表的最有效方法是什么?请注意,其中涉及两个自定义类 代码中的一般学生列表称为lststusts。这是我想从中删除任何重复项的列表 (我试图想出一个更好的例子,但这是我现在能做的最好的例子。) 我不必使用LINQ,但它是可用的。MoreLinq也可以使用 以下是我的课程:C#从包含列表的列表中删除重复项,c#,linq,C#,Linq,假设我们有一份“a学生”名单和一份“B学生”名单。然后,我们将这两个列表添加到一个更通用的列表中,称为“学生”。然后,有人决定在普通的“学生”列表中添加一个重复的“a学生”列表,从而使我们的生活复杂化。删除“A学生”重复列表的最有效方法是什么?请注意,其中涉及两个自定义类 代码中的一般学生列表称为lststusts。这是我想从中删除任何重复项的列表 (我试图想出一个更好的例子,但这是我现在能做的最好的例子。) 我不必使用LINQ,但它是可用的。MoreLinq也可以使用 以下是我的课程: pub
public class Student
{
public Student(string _name, int _age, Exam _lastExam)
{
name = _name;
age = _age;
lastExam = _lastExam;
}
public string name { get; set; }
public int age { get; set; }
public Exam lastExam { get; set; }
}
public class Exam
{
public Exam(int _correct, int _possible)
{
correct = _correct;
possible = _possible;
}
public int correct { get; set; }
public int possible { get; set; }
}
下面是造成混乱的代码:
List<List<Student>> lstStudents = new List<List<Student>>();
List<Student> lstAStudents = new List<Student>();
List<Student> lstDuplicateAStudents = new List<Student>();
List<Student> lstBStudents = new List<Student>();
// Create a list of some A students
lstAStudents.Add(new Student("Alex", 14, new Exam(98,100)));
lstAStudents.Add(new Student("Kim", 13, new Exam(96, 100)));
lstAStudents.Add(new Student("Brian", 14, new Exam(92, 100)));
lstStudents.Add(lstAStudents);
// Create a duplicate list of A students
lstDuplicateAStudents.Add(new Student("Alex", 14, new Exam(98, 100)));
lstDuplicateAStudents.Add(new Student("Kim", 13, new Exam(96, 100)));
lstDuplicateAStudents.Add(new Student("Brian", 14, new Exam(92, 100)));
lstStudents.Add(lstDuplicateAStudents);
// Create a list of some B students
lstBStudents.Add(new Student("John", 13, new Exam(88, 100)));
lstBStudents.Add(new Student("Jenny", 13, new Exam(80, 100)));
lstBStudents.Add(new Student("Jamie", 15, new Exam(81, 100)));
lstStudents.Add(lstBStudents);
List lststudens=newlist();
List lstAStudents=新列表();
List lstDuplicateAStudents=新列表();
List lstBStudents=新列表();
//创建一些学生的列表
添加(新学生(“Alex”,14岁,新考试(98100));
添加(新学生(“Kim”,13岁,新考试(96100));
添加(新学生(“Brian”,14岁,新考试(92100));
lstStudents.Add(lstStudents);
//创建学生的重复列表
添加(新学生(“Alex”,14岁,新考试(98100));
添加(新学生(“Kim”,13岁,新考试(96100));
添加(新学生(“Brian”,14岁,新考试(92100));
添加(lstDuplicateStudents);
//创建一些B学生的列表
增加(新学生(“约翰”,13岁,新考试(88100));
添加(新学生(“珍妮”,13岁,新考试(80100));
添加(新学生(“Jamie”,15岁,新考试(81100));
添加(lstBStudents);
或许您可以持有一套可累积独特列表的物品:
var set = new HashSet<List<Student>>(new CustomComparer());
foreach (List<List<Student>> list in source)
{
if (set.Contains(list))
continue;
set.Add(list)
}
public class CustomComparer : IEqualityComparer<List<Student>>
{
public bool Equals(List<Student> one, List<Student> two)
{
if (one.Count != two.Count) return false;
// simplest possible code to compare two lists
// warning: runs in O(N*logN) for each compare
return one.OrderBy(s=>s).SequenceEqual(two.OrderBy(s=>s));
}
public int GetHashCodeList<Student> item)
{
int ret = -1;
foreach (var s in item)
ret ^= s.GetHashCode();
return ret;
}
}
var set=newhashset(newcustomcomparer());
foreach(源中的列表)
{
if(集合包含(列表))
继续;
set.Add(列表)
}
公共类CustomComparer:IEqualityComparer
{
公共布尔等于(列表一、列表二)
{
如果(one.Count!=two.Count)返回false;
//比较两个列表的最简单代码
//警告:每次比较都以O(N*logN)运行
返回一个.OrderBy(s=>s).SequenceEqual(两个.OrderBy(s=>s));
}
public int GetHashCodeList项)
{
int-ret=-1;
foreach(项目中的var s)
ret^=s.GetHashCode();
返回ret;
}
}
此解决方案的主要问题是用于比较两个列表的代码。以不同顺序包含相同元素的列表是否被视为相等?如果是,我们需要通过对每个列表进行预排序(以节省比较时间)来更改顺序,或者每次对每个列表的副本进行排序,这将导致额外的时间损失。所以我想主要的问题是你的名单有多大。对于低于1000学生/100列表的值,性能问题不应明显
另一个问题是GetHashCode实现——它是O(N),我们没有地方缓存计算值,因为List是一个框架结构。为了解决这个问题,我建议引入StudentList类,它将具有comparer(现在我们必须在外部指定它),并通过缓存获取哈希代码
此外,还有一个更好的可用列表实现。您可能可以持有一套可累积唯一列表的集合:
var set = new HashSet<List<Student>>(new CustomComparer());
foreach (List<List<Student>> list in source)
{
if (set.Contains(list))
continue;
set.Add(list)
}
public class CustomComparer : IEqualityComparer<List<Student>>
{
public bool Equals(List<Student> one, List<Student> two)
{
if (one.Count != two.Count) return false;
// simplest possible code to compare two lists
// warning: runs in O(N*logN) for each compare
return one.OrderBy(s=>s).SequenceEqual(two.OrderBy(s=>s));
}
public int GetHashCodeList<Student> item)
{
int ret = -1;
foreach (var s in item)
ret ^= s.GetHashCode();
return ret;
}
}
var set=newhashset(newcustomcomparer());
foreach(源中的列表)
{
if(集合包含(列表))
继续;
set.Add(列表)
}
公共类CustomComparer:IEqualityComparer
{
公共布尔等于(列表一、列表二)
{
如果(one.Count!=two.Count)返回false;
//比较两个列表的最简单代码
//警告:每次比较都以O(N*logN)运行
返回一个.OrderBy(s=>s).SequenceEqual(两个.OrderBy(s=>s));
}
public int GetHashCodeList项)
{
int-ret=-1;
foreach(项目中的var s)
ret^=s.GetHashCode();
返回ret;
}
}
此解决方案的主要问题是用于比较两个列表的代码。以不同顺序包含相同元素的列表是否被视为相等?如果是,我们需要通过对每个列表进行预排序(以节省比较时间)来更改顺序,或者每次对每个列表的副本进行排序,这将导致额外的时间损失。所以我想主要的问题是你的名单有多大。对于低于1000学生/100列表的值,性能问题不应明显
另一个问题是GetHashCode实现——它是O(N),我们没有地方缓存计算值,因为List是一个框架结构。为了解决这个问题,我建议引入StudentList类,它将具有comparer(现在我们必须在外部指定它),并通过缓存获取哈希代码
此外,还有一个更好的可用实现。您可以用于学生
和考试
:
public class Student: IEquatable<Student>
{
...
public bool Equals(Student other)
{
return name == other.name && age == other.age
&& lastExam.Equals(other.lastExam);
}
public override bool Equals(object obj)
{
Student student = obj as Student;
return Equals(student);
}
public override int GetHashCode()
{
return name.GetHashCode() ^
age.GetHashCode() ^ lastExam.GetHashCode();
}
}
public class Exam: IEquatable<Exam>
{
...
public bool Equals(Exam exam)
{
return exam.correct == correct && exam.possible == possible;
}
public override bool Equals(object obj)
{
Exam exam = obj as Exam;
return Equals(exam);
}
public override int GetHashCode()
{
return correct.GetHashCode() ^ possible.GetHashCode();
}
}
然后为列表构建自定义IQualityComparer
:
您可以同时用于学生
和考试
:
public class Student: IEquatable<Student>
{
...
public bool Equals(Student other)
{
return name == other.name && age == other.age
&& lastExam.Equals(other.lastExam);
}
public override bool Equals(object obj)
{
Student student = obj as Student;
return Equals(student);
}
public override int GetHashCode()
{
return name.GetHashCode() ^
age.GetHashCode() ^ lastExam.GetHashCode();
}
}
public class Exam: IEquatable<Exam>
{
...
public bool Equals(Exam exam)
{
return exam.correct == correct && exam.possible == possible;
}
public override bool Equals(object obj)
{
Exam exam = obj as Exam;
return Equals(exam);
}
public override int GetHashCode()
{
return correct.GetHashCode() ^ possible.GetHashCode();
}
}
然后为列表构建自定义IQualityComparer
:
除了
Linq方法外,是否使用?创建一个集合
并将其转换回一个列表
(该列表将删除所有重复项,因为集合
不能有重复的成员)?确保您选择了正确的字段按onUse进行分组,除了Linq方法?创建一个集合
并将其转换回一个列表
(该列表将删除所有重复项,因为集合
不能有重复的成员)?确保您选择了正确的字段进行分组,感谢您的回复。对于我的特殊情况,每个列表中学生的顺序并不重要。(因为我的例子不太好,所以我应该具体说明一下。)我决定将孔乐的答案标记为正确,因为它(几乎完全)符合我的要求,但你帮助我更好地理解了应该如何处理这个问题。Tha