Как я использую интерфейс IComparable?

17
задан Bob Kaufman 20 December 2012 в 02:46
поделиться

4 ответа

Ну, так как Вы используете 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 на 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)));
    }
}
14
ответ дан 30 November 2019 в 12:44
поделиться

Вот простой пример:

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();
    }
}

"Показывают мне как!"

Хорошо, так как Вы спросили так приятно.

static class Program
{
    static void Main()
    {

        List<SortableItem> items = new List<SortableItem>();
        SortableItem temp = new SortableItem();
        temp.someString = "Hello";
        temp.someNumber = 1;
        items.Add(temp);
        temp = new SortableItem();
        temp.someString = "World";
        temp.someNumber = 2;
        items.Add(temp);
        SortByString(items);
        Output(items);
        SortAscending(items);
        Output(items);
        SortByNumber(items);
        Output(items);
        SortDescending(items);
        Output(items);
        Console.ReadKey();
    }

    public static void SortDescending(List<SortableItem> items)
    {
        foreach (SortableItem item in items)
            item.descending = true;
    }
    public static void SortAscending(List<SortableItem> items)
    {
        foreach (SortableItem item in items)
            item.descending = false;
    }
    public static void SortByNumber(List<SortableItem> items)
    {
        foreach (SortableItem item in items)
            item.sortField = SortableItem.SortFieldType.SortNumber;
    }
    public static void SortByString(List<SortableItem> items)
    {
        foreach (SortableItem item in items)
            item.sortField = SortableItem.SortFieldType.SortString;
    }
    public static void Output(List<SortableItem> items)
    {
        items.Sort();
        for (int i = 0; i < items.Count; i++)
            Console.WriteLine("Item " + i + ": " + items[i].ToString());
    }
}
10
ответ дан 30 November 2019 в 12:44
поделиться

Если Вы хотите динамический вид, можно использовать 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 ) );
4
ответ дан 30 November 2019 в 12:44
поделиться

Это не могло бы быть относительно порядка сортировки, но это все еще - я думаю - интересное использование 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)
}
0
ответ дан 30 November 2019 в 12:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: