按字母顺序排序 List<T>

485

我正在使用 Framework 3.5 上的 C#。我希望能够快速对一个泛型 List<T> 进行排序。为了举例,假设我有一个 Person 类型的 List,其中包含一个 lastname 属性。我该如何使用 lambda 表达式对这个 List 进行排序呢?

List<Person> people = PopulateList();
people.OrderBy(???? => ?????)
10个回答

744

如果您需要进行原地排序(即更新列表本身):

people.Sort((x, y) => string.Compare(x.LastName, y.LastName));

如果你想创建一个新的列表:

var newList = people.OrderBy(x=>x.LastName).ToList(); // ToList optional

36
@James:我不这么认为。Comparison<T> 返回的是 int,而不是 bool。 - Jon Skeet
67
var newList = people.OrderBy(x=>x.FirstName).ThenBy(x=>x.LastName).ToList();新的列表 = 按照人物的名字(FirstName)升序排列,如果名字相同则按照姓氏(LastName)升序排列,最后将结果转换为列表。 - Marc Gravell
2
如何在数据类型为int时进行排序。使用int.Compare函数。 - user2603796
2
@Faraz 只需使用 x.CompareTo(y)。对于字符串来说,这更棘手,因为 a: 空值,b: 不同的排序字符串方式(大小写敏感性、文化等)。 - Marc Gravell
4
@Faraz (x, y) => x.price.CompareTo(y.price)这段代码是C#语言的语法,它的功能是比较x和y的价格并返回一个整数值。具体来说,它使用了一个名为"CompareTo"的方法,该方法对两个对象进行比较,并返回一个值来表示它们之间的关系。如果x的价格小于y的价格,则返回小于0的值;如果它们的价格相等,则返回0;如果x的价格大于y的价格,则返回大于0的值。 - Marc Gravell
显示剩余4条评论

107

您需要在原地对列表进行排序,还是只需要一个有序的列表内容序列? 后者更容易:

var peopleInOrder = people.OrderBy(person => person.LastName);

要进行就地排序,您需要一个 IComparer<Person> 或者一个 Comparison<Person>。为此,您可以考虑在 MiscUtil 中使用 ProjectionComparer

(我知道我一直提到 MiscUtil - 它只是一直很相关...)


1
这对我有用,但只有在我添加“.ToList()”之后才有效: contemporariesOrderedByBirthYear = contemporaries.OrderBy(contemp => contemp.BirthYear).ToList(); - B. Clay Shannon-B. Crow Raven
2
@B.ClayShannon:如果你想要一个List<T>,那么你需要它,但是如果你只想迭代,那么你不需要它。 - Jon Skeet

28
people.OrderBy(person => person.lastname).ToList();

18
好的,这依然不能捕捉到结果 - 你需要在左边加上"List<Person> people = "… - Marc Gravell
9
这个答案展示了在使用LINQ时最常见的错误 - 像OrderBy这样的方法不会修改列表,而是返回一个新的“集合”(通常是惰性的IEnumerable<T>),需要将其分配给某些东西。 - Alexei Levenkov
2
@AlexeiLevenkov,你怎么知道在使用LINQ时这是最常见的错误? - tymtam

25

你可以使用 LINQ :) 使用:

System.linq;
var newList = people.OrderBy(x=>x.Name).ToList();

15
private void SortGridGenerico< T >(
          ref List< T > lista       
    , SortDirection sort
    , string propriedadeAOrdenar)
{

    if (!string.IsNullOrEmpty(propriedadeAOrdenar)
    && lista != null
    && lista.Count > 0)
    {

        Type t = lista[0].GetType();

        if (sort == SortDirection.Ascending)
        {

            lista = lista.OrderBy(
                a => t.InvokeMember(
                    propriedadeAOrdenar
                    , System.Reflection.BindingFlags.GetProperty
                    , null
                    , a
                    , null
                )
            ).ToList();
        }
        else
        {
            lista = lista.OrderByDescending(
                a => t.InvokeMember(
                    propriedadeAOrdenar
                    , System.Reflection.BindingFlags.GetProperty
                    , null
                    , a
                    , null
                )
            ).ToList();
        }
    }
}

6
您也可以使用。
model.People = model.People.OrderBy(x => x.Name).ToList();

4
虽然这段代码示例可能回答了问题,但它缺乏解释。目前而言,它没有增加任何价值,并有被投票降低或删除的风险。请添加一些说明,解释它是如何解决原帖中所提出的问题的。 - oɔɯǝɹ

6

对我来说,这个有用的虚拟指南 - 在通用列表中进行排序 - 很有用。 它可以帮助您理解4种方法(重载)以非常完整和清晰的解释和简单的示例完成此工作。

  • List.Sort()
  • List.Sort(Generic Comparison)
  • List.Sort(Generic IComparer)
  • List.Sort(Int32, Int32, Generic IComparer)

Sort()非常有用,特别是在List<string>()的情况下。 - Vyas Bharghava

6
您可以使用此代码片段:
var New1 = EmpList.OrderBy(z => z.Age).ToList();

其中New1是一个List<Employee>

EmpList是一个List<Employee>类型的变量。

z是一个Employee类型的变量。


AnshuMan,不存在var类型。New1List<Employee>,而zEmployee - nawfal
@nawfal 在C#中有一个var类型。或者你也可以使用dynamic代替var。 - Dhruv Badaya
@lightlessdays var是一个关键字,在C#中没有var类型。不要在这种情况下使用dynamic。 - nawfal

2

这是一个通用的排序器。通过下面的开关调用。

dvm.PagePermissions是我的ViewModel上的一个属性,类型为List T,在此情况下,T是名为page_permission的EF6模型类。

dvm.UserNameSortDir是ViewModel上的字符串属性,保存下一个排序方向。实际在视图中使用的方向。

switch (sortColumn)
{
    case "user_name":
        dvm.PagePermissions = Sort(dvm.PagePermissions, p => p.user_name, ref sortDir);
        dvm.UserNameSortDir = sortDir;
        break;
    case "role_name":
        dvm.PagePermissions = Sort(dvm.PagePermissions, p => p.role_name, ref sortDir);
        dvm.RoleNameSortDir = sortDir;
        break;
    case "page_name":
        dvm.PagePermissions = Sort(dvm.PagePermissions, p => p.page_name, ref sortDir);
        dvm.PageNameSortDir = sortDir;
        break;
}                 


public List<T> Sort<T,TKey>(List<T> list, Func<T, TKey> sorter, ref string direction)
    {
        if (direction == "asc")
        {
            list = list.OrderBy(sorter).ToList();
            direction = "desc";
        }
        else
        {
            list = list.OrderByDescending(sorter).ToList();
            direction = "asc";
        }
        return list;
    }

1
我认为这太复杂了。正如您在其他答案中所看到的,所有操作都可以在一行代码中完成(这并不一定意味着在一行代码中完成是好的,但我不明白这样做的优势在哪里)。 - jalgames
这是使用AngularJS进行多列排序的内容。它本质上是单行排序,但它还设置了排序方向变量。如果你仔细看它,它其实并不那么复杂。我猜Sort函数可能有点吓人,因为它包含了所有通用的东西,但如果我把那个定义拿出来,它就是一个1行的Sort调用。 - howserss
对于 Op 请求来说太复杂了。不过对于另一个问题来说是一个好的解决方案。 - rollsch

0
在 .NET 7 预览版中,您可以使用 System.Linq简化排序。它还具有一些性能改进。
var sorted = people.Order();

此外,需要注意Sort方法在大多数情况下具有更好的性能,因为不需要分配新列表。

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