Как использовать интерфейс IComparable?
Мне нужен основной пример того, как использовать IComparable
интерфейс, чтобы я мог Сортировать по возрастанию или убыванию и по различным полям типа объекта, который я сортирую.
6 ответов
Ну, так как вы используете List<T>
было бы намного проще просто использовать Comparison<T>
, например:
List<Foo> data = ...
// sort by name descending
data.Sort((x,y) => -x.Name.CompareTo(y.Name));
конечно, с LINQ вы можете просто использовать:
var ordered = data.OrderByDescending(x=>x.Name);
но вы можете представить это в List<T>
(для повторного заказа) довольно легко; Вот пример, который позволяет Sort
on List<T>
С лямбда-синтаксис:
using System;
using System.Collections.Generic;
class Foo { // formatted for vertical space
public string Bar{get;set;}
}
static class Program {
static void Main() {
List<Foo> data = new List<Foo> {
new Foo {Bar = "abc"}, new Foo {Bar = "jkl"},
new Foo {Bar = "def"}, new Foo {Bar = "ghi"}
};
data.SortDescending(x => x.Bar);
foreach (var row in data) {
Console.WriteLine(row.Bar);
}
}
static void Sort<TSource, TValue>(this List<TSource> source,
Func<TSource, TValue> selector) {
var comparer = Comparer<TValue>.Default;
source.Sort((x,y)=>comparer.Compare(selector(x),selector(y)));
}
static void SortDescending<TSource, TValue>(this List<TSource> source,
Func<TSource, TValue> selector) {
var comparer = Comparer<TValue>.Default;
source.Sort((x,y)=>comparer.Compare(selector(y),selector(x)));
}
}
вот простой пример:
public class SortableItem : IComparable<SortableItem>
{
public int someNumber;
#region IComparable<SortableItem> Members
public int CompareTo(SortableItem other)
{
int ret = -1;
if (someNumber < other.someNumber)
ret = -1;
else if (someNumber > other.someNumber)
ret = 1;
else if (someNumber == other.someNumber)
ret = 0;
return ret;
}
#endregion
}
простой. Все, что нам нужно сделать, это добавить несколько полей к объекту. Сначала мы добавим строку для другого типа сортировки, а затем добавим логическое значение, чтобы указать, сортируем ли мы в порядке убывания или возрастания, а затем добавим поле, которое определяет, какое поле мы хотим искать от.
public class SortableItem : IComparable<SortableItem>
{
public enum SortFieldType { SortNumber, SortString }
public int someNumber = -1;
public string someString = "";
public bool descending = true;
public SortFieldType sortField = SortableItem.SortFieldType.SortNumber;
#region IComparable<SortableItem> Members
public int CompareTo(SortableItem other)
{
int ret = -1;
if(sortField == SortableItem.SortFieldType.SortString)
{
// A lot of other objects implement IComparable as well.
// Take advantage of this.
ret = someString.CompareTo(other.someString);
}
else
{
if (someNumber < other.someNumber)
ret = -1;
else if (someNumber > other.someNumber)
ret = 1;
else if (someNumber == other.someNumber)
ret = 0;
}
// A quick way to switch sort order:
// -1 becomes 1, 1 becomes -1, 0 stays the same.
if(!descending) ret = ret * -1;
return ret;
}
#endregion
public override string ToString()
{
if(sortField == SortableItem.SortFieldType.SortString)
return someString;
else
return someNumber.ToString();
}
}
Если вы хотите динамическую сортировку, вы можете использовать LINQ
var itemsOrderedByNumber = ( from item in GetClasses() orderby item.Number select item ).ToList();
var itemsOrderedByText = ( from item in GetClasses() orderby item.Text select item ).ToList();
var itemsOrderedByDate = ( from item in GetClasses() orderby item.Date select item ).ToList();
или метод "сортировки" класса списка:
List<Class1> itemsOrderedByNumber2 = new List<Class1>( GetClasses() );
itemsOrderedByNumber2.Sort( ( a, b ) => Comparer<int>.Default.Compare( a.Number, b.Number ) );
List<Class1> itemsOrderedByText2 = new List<Class1>( GetClasses() );
itemsOrderedByText2.Sort( ( a, b ) => Comparer<string>.Default.Compare( a.Text, b.Text ) );
List<Class1> itemsOrderedByDate2 = new List<Class1>( GetClasses() );
itemsOrderedByDate2.Sort( ( a, b ) => Comparer<DateTime>.Default.Compare( a.Date, b.Date ) );
вы можете использовать это для сортировки списка
namespace GenaricClass
{
class Employee :IComparable<Employee>
{
public string Name { get; set; }
public double Salary { get; set; }
public int CompareTo(Employee other)
{
if (this.Salary < other.Salary) return 1;
else if (this.Salary > other.Salary) return -1;
else return 0;
}
public static void Main()
{
List<Employee> empList = new List<Employee>()
{
new Employee{Name="a",Salary=140000},
new Employee{Name="b",Salary=120000},
new Employee{Name="c",Salary=160000},
new Employee{Name="d",Salary=10000}
};
empList.Sort();
foreach (Employee emp in empList)
{
System.Console.Write(emp.Salary +",");
}
System.Console.ReadKey();
}
}
}
это может быть не в отношении порядка сортировки, но это все еще - я думаю - интересное использование IComparable
:
public static void MustBeInRange<T>(this T x, T minimum, T maximum, string paramName)
where T : IComparable<T>
{
bool underMinimum = (x.CompareTo(minimum) < 0);
bool overMaximum = (x.CompareTo(maximum) > 0);
if (underMinimum || overMaximum)
{
string message = string.Format(
System.Globalization.CultureInfo.InvariantCulture,
"Value outside of [{0},{1}] not allowed/expected",
minimum, maximum
);
if (string.IsNullOrEmpty(paramName))
{
Exception noInner = null;
throw new ArgumentOutOfRangeException(message, noInner);
}
else
{
throw new ArgumentOutOfRangeException(paramName, x, message);
}
}
}
public static void MustBeInRange<T>(this T x, T minimum, T maximum)
where T : IComparable<T> { x.MustBeInRange(minimum, maximum, null); }
эти простые методы расширения позволяют выполнять проверку диапазона параметров для любого типа, который реализует IComparable
такой:
public void SomeMethod(int percentage, string file) {
percentage.MustBeInRange(0, 100, "percentage");
file.MustBeInRange("file000", "file999", "file");
// do something with percentage and file
// (caller will have gotten ArgumentOutOfRangeExceptions when applicable)
}
using System;
using System.Collections.Generic;
using System.Text;
namespace Sorting_ComplexTypes
{
class Program
{
static void Main(string[] args)
{
Customer customer1 = new Customer {
ID = 101,
Name = "Mark",
Salary = 2400,
Type = "Retail Customers"
};
Customer customer2 = new Customer
{
ID = 102,
Name = "Brian",
Salary = 5000,
Type = "Retail Customers"
};
Customer customer3 = new Customer
{
ID = 103,
Name = "Steve",
Salary = 3400,
Type = "Retail Customers"
};
List<Customer> customer = new List<Customer>();
customer.Add(customer1);
customer.Add(customer2);
customer.Add(customer3);
Console.WriteLine("Before Sorting");
foreach(Customer c in customer)
{
Console.WriteLine(c.Name);
}
customer.Sort();
Console.WriteLine("After Sorting");
foreach(Customer c in customer)
{
Console.WriteLine(c.Name);
}
customer.Reverse();
Console.WriteLine("Reverse Sorting");
foreach (Customer c in customer)
{
Console.WriteLine(c.Name);
}
}
}
}
public class Customer : IComparable<Customer>
{
public int ID { get; set; }
public string Name { get; set; }
public int Salary { get; set; }
public string Type { get; set; }
public int CompareTo(Customer other)
{
return this.Name.CompareTo(other.Name);
}
}