我希望通过多个属性比较两个对象。
我们说我有一个名为学生的班级,每个学生都有名字和分数。我的愿望是创建一个SortedSet(在这里实现一个Comparer ),所以每当我将一个学生添加到该集合中时,他们将按照他们的分数进行排序,如果他们具有相同的分数,他们将按照他们的名字按字母顺序排列。
Java 8相当于:
TreeSet<Student> students = new TreeSet<>(
Comparator.comparing(Student::getScore).thenComparing(Student::getName)
);
这可以使用Comparer<Student>.Create()
还是以其他任何方式实现?
答案 0 :(得分:3)
您可以将SortedSet
与自定义比较器一起使用。实施有点棘手:
var s = new SortedSet<Student>(
Comparer<Student>.Create((a, b) => {
// This code implements comparison by score first
var res= a.Score.CompareTo(b.Score);
// Ties are resolved by name in alphabetic order
return res != 0 ? res : a.Name.CompareTo(b.Name);
})
);
答案 1 :(得分:2)
我放在一起的两个简单示例,您可以使用Student
类型class Program
{
static void Main(string[] args)
{
var set = new SortedSet<Student>(new StudentComparer());
set.Add(new Student {Name = "Test", Score = 10});
set.Add(new Student { Name = "Tom", Score = 5 });
set.Add(new Student { Name = "Adam", Score = 90 });
set.Add(new Student { Name = "Adam", Score = 85 });
foreach (var setItem in set)
{
Debug.WriteLine($@"{setItem.Name} - {setItem.Score}");
}
/* outputs:
Tom - 5
Test - 10
Adam - 85
Adam - 90
*/
}
}
class Student
{
public string Name { get; set; }
public int Score { get; set; }
}
class StudentComparer : IComparer<Student>
{
public int Compare(Student x, Student y)
{
var result = x.Score.CompareTo(y.Score);
if (result == 0)
{
result = x.Name.CompareTo(y.Name);
}
return result;
}
}
。然后,您将按照所需的顺序进行比较:
var students = new List<Student>
{
new Student {Name = "Test", Score = 10},
new Student {Name = "Tom", Score = 5},
new Student {Name = "Adam", Score = 90},
new Student {Name = "Adam", Score = 85}
};
var orderedList = students.OrderByDescending(s => s.Score)
.ThenBy(s => s.Name);
foreach (var student in orderedList)
{
Debug.WriteLine($@"{student.Name} - {student.Score}");
}
/* outputs:
Adam - 90
Adam - 85
Test - 10
Tom - 5
*/
您也可以使用普通列表,并使用Linq:
processBackground()
答案 2 :(得分:0)
您可以使用SortedSet
generic并提供IComparer<Student>
根据您想要的顺序进行比较,即首先比较得分,如果它们相同则比较名称
class Program
{
static void Main(string[] args)
{
var students = new List<Student>()
{
new Student()
{
Score = 10,
Name = "David"
},
new Student()
{
Score = 4,
Name = "Nik"
},
new Student()
{
Score = 10,
Name = "Randy"
}
};
SortedSet<Student> sortedStudents = new SortedSet<Student>(new StudentMultiCriteria());
foreach (var student in students)
{
sortedStudents.Add(student);
}
foreach (var sortedStudent in sortedStudents)
{
Console.WriteLine(sortedStudent);
}
}
}
class Student
{
public int Score { get; set; }
public string Name { get; set; }
public override string ToString()
{
return $"Score {Score}, Name {Name}";
}
}
class StudentMultiCriteria : IComparer<Student>
{
public int Compare(Student x, Student y)
{
// You do the comparison based on different fields here
return x.Score.CompareTo(y.Score) == 0 ? x.Name.CompareTo(y.Name) : x.Score.CompareTo(y.Score);
}
}
答案 3 :(得分:0)
我的不好,在我的评论中我应该说Icomparable<Student>
。这将允许排序集合使用默认比较器。另外在我看来,当这样排序时,通常分数将按降序排序,但名称会升序。因此,您的课程可能如下所示:
class Student : IComparable<Student>
{
public int score = 0;
public string name = "";
public int CompareTo(Student other)
{
if (score == other.score)
{
return name.CompareTo(other.name);
}
else
{
return other.score.CompareTo(score);
}
}
}
static void Main()
{
SortedSet<Student> students = new SortedSet<Student>();
students.Add(new Student { score = 20, name = "abcd" });
students.Add(new Student { score = 10, name = "bcde" });
students.Add(new Student { score = 10, name = "acde" });
students.Add(new Student { score = 30, name = "cdef" });
students.Add(new Student { score = 10, name = "abce" });
}
结果看起来像这样:
30, “CDEF”
20, “ABCD”
10, “ABCE”
10, “ACDE”
10, “BCDE”
答案 4 :(得分:0)
您可以编写一个通用比较器来模仿该API:
public class Comparator<T> : Comparer<T>
{
readonly List<Func<T, T, int>> m_comparisons = new List<Func<T, T, int>>();
Comparator()
{
}
public static Comparator<T> Comparing<TProp>(Func<T, TProp> property)
where TProp : IComparable<TProp>
{
return new Comparator<T>().ThenComparing(property);
}
public static Comparator<T> ComparingDescending<TProp>(Func<T, TProp> property)
where TProp : IComparable<TProp>
{
return new Comparator<T>().ThenComparingDescending(property);
}
public static Comparator<T> Comparing<TProp>(Func<T, TProp> property, IComparer<TProp> propertyComparer)
{
return new Comparator<T>().ThenComparing(property, propertyComparer);
}
public static Comparator<T> ComparingDescending<TProp>(Func<T, TProp> property, IComparer<TProp> propertyComparer)
{
return new Comparator<T>().ThenComparingDescending(property, propertyComparer);
}
public Comparator<T> ThenComparing<TProp>(Func<T, TProp> property)
where TProp : IComparable<TProp>
{
return ThenComparing(property, Comparer<TProp>.Default);
}
public Comparator<T> ThenComparingDescending<TProp>(Func<T, TProp> property)
where TProp : IComparable<TProp>
{
return ThenComparingDescending(property, Comparer<TProp>.Default);
}
public Comparator<T> ThenComparing<TProp>(Func<T, TProp> property, IComparer<TProp> propertyComparer)
{
m_comparisons.Add((t1, t2) => propertyComparer.Compare(property(t1), property(t2)));
return this;
}
public Comparator<T> ThenComparingDescending<TProp>(Func<T, TProp> property, IComparer<TProp> propertyComparer)
{
m_comparisons.Add((t1, t2) => propertyComparer.Compare(property(t2), property(t1)));
return this;
}
public override int Compare(T x, T y)
{
foreach (Func<T, T, int> comparison in m_comparisons)
{
int result = comparison(x, y);
if (result != 0)
{
return result;
}
}
// They are equal.
return 0;
}
}
用法:
SortedSet<Student> students = new SortedSet<Student>(Comparator
.Comparing(x => Score)
.ThenComparing(x => x.Name)); // etc.
与使用Comparer<Student>.Create
来构造一个大型lambda相比,我发现这更具可读性和安全性。