如何对IList<Class>进行排序?

11

IList 没有 Sort() 函数,有人能帮我吗?我想对我的 IList 进行排序。

假设这是我的 IList:

public class MyObject() 
{
 public int number { get; set; }
 public string marker { get; set; }
}

如何使用标记字符串对myobj进行排序?

public void SortObject()
{
 IList<MyObject> myobj = new List<MyObject>();
}

1
myobj 一直都是 List 吗?如果是,你可以将其转换为 List 并运行它的 Sort 函数。 - Gabe
6个回答

18

使用OrderBy

示例

public class MyObject() 
{
    public int number { get; set; }
    public string marker { get; set; }
}

IList<MyObject> myobj = new List<MyObject>();
var orderedList = myobj.OrderBy(x => x.marker).ToList();

为了不区分大小写,您应该使用IComparer。

public class CaseInsensitiveComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
    }
}

IList<MyObject> myobj = new List<MyObject>();
var orderedList = myobj.OrderBy(x => x.marker, new CaseInsensitiveComparer()).ToList();

1
+1 考虑大小写敏感性,但框架已经有不区分大小写的字符串比较器了,无需创建一个新的。请尝试使用 StringComparer.OrdinalIgnoreCase 替代您的 CaseInsensitiveComparer。 - Joe

11

我建议不要使用 OrderBy 来对列表进行排序,因为它是一个LINQ扩展方法,因此:

  • 它将列表封装在可枚举类型中,然后枚举并填充一个新的临时列表,再对该新列表进行排序。
  • 它将排序后的列表再次封装在另一个可枚举类型中。
  • 当你调用 ToList() 方法时,它会枚举并填充另一个新列表。

实质上:除了实际排序外,它还创建和填充了2个新列表和2个可枚举类型。相比之下,List.Sort() 可以就地排序,不创建任何东西,因此更有效率。

我的建议是:

  • 如果你知道列表的基础类型,使用 List.Sort()Array.Sort(array)
  • 如果你不知道列表的基础类型,将列表复制到临时数组中,然后使用 Array.Sort(array) 进行排序并返回它。

0

关于为什么不要使用 OrderBy 或类似的,请参阅 Christophe's answer

这里是一种尝试快速排序的方法:

public static void Sort<T>(this IList<T> ilist)
{
    switch(ilist)
    {
        case List<T> lst:
            lst.Sort();
            break;
        case Array arr:
            Array.Sort(arr);
            break;
        default:
            throw new NotImplementedException();
            // or add slow impl if you don't want this to fail!!
    }
}

0

OrderBy 肯定能完成任务,但我个人更喜欢 List.Sort 的语法,因为你可以提供一个 Comparison<T> 委托而不必编写实现 IComparer<T> 接口的类。我们可以通过扩展方法来实现这个目标,如果你感兴趣的话,可以查看 SortExtensions:

http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/


0
var sorted = myObj.OrderBy(x => x.marker);

0

要进行原地排序,您基本上会看到这两种方法:

        IList<T> list = .... // your ilist
        var sorted = list.ToArray();
        Array.Sort(sorted);

        for (int i = 0; i < list.Count; i++)
        {
            list[i] = sorted[i];
        }

并且

        IList<T> list = .... // your ilist
        ArrayList.Adapter((IList)list).Sort();

第二个可能看起来更简单,但对于值类型集合来说并不是很好,因为它会产生装箱开销。此外,不能保证您的IList将实现IList接口。在我看来,第一个更好。

您也可以使用第一种方法来原地排序 ICollection<T>,但是是否应该公开这样的功能还有疑问,因为 ICollection<T> 的契约并不保证顺序(考虑哈希结构)。无论如何,以下是代码示例:

    ICollection<T> collection = .... // your icollection
    var sorted = collection.ToArray();
    Array.Sort(sorted);

    collection.Clear();
    foreach (var i in sorted)
    {
       collection.Add(i);
    }

关于排序稳定性的说明,.NET的数组/列表排序算法是不稳定的。如果要进行稳定排序,您必须使用

        IList<T> list = .... // your ilist
        var sorted = list.OrderBy(i => i).ToArray();

        for (int i = 0; i < list.Count; i++)
        {
            list[i] = sorted[i];
        }

这不能像不稳定排序那样快。


最后,为了得到一个完整的答案,也许采用watbywbarif提出的综合方法更好:

    public static void Sort<T>(this IList<T> list, IComparer<T> comparer, bool stable)
    {
        if (stable)
        {
            list.StableSort(comparer);
        }
        else
        {
            list.UnstableSort(comparer);
        }
    }

    static void StableSort<T>(this IList<T> list, IComparer<T> comparer)
    {
        list.OrderBy(x => x, comparer).CopyTo(list);
    }

    static void UnstableSort<T>(this IList<T> list, IComparer<T> comparer)
    {
        switch (list)
        {
            case List<T> l:
                l.Sort(comparer);
                break;

            case T[] a:
                Array.Sort(a, comparer);
                break;

            default:
                T[] sortable = list.ToArray();
                sortable.UnstableSort(comparer);
                sortable.CopyTo(list);
                break;
        }
    }

    static void CopyTo<T>(this IEnumerable<T> source, IList<T> target)
    {
        int i = 0;
        foreach (T item in source)
        {
            target[i++] = item;
        }
    }

这就是内置方法所能达到的限度。为了更快的实现,你需要自己动手编写代码,参考:https://stackoverflow.com/a/19167475


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接