按两个属性就地对列表进行排序

3

我有一个包含两个属性的类,分别是Name和Position。我想按照Position对该类的列表进行排序,位置相同的元素应该按照Name进行排序。我正在处理静态列表,所以我希望能够就地进行操作。

到目前为止,我已经成功按照一个属性对列表进行了排序:

list.Sort((x, y) => x.Position.CompareTo(y.Position));

这段代码有效,而且我已经按照Position对列表进行了排序,但是我不知道如何实现第二部分。我找到了这个问题,但是我不理解答案。

有人可以帮助我吗?

3个回答

8
我会使用 "OrderBy" 和 "ThenBy" 来实现排序:
  IEnumerable<Person> orderedPersons = persons.OrderBy(item => item.Position)
            .ThenBy(item => item.Name);

这绝对是最可靠的方法。 - undefined
2
这是按照两个属性排序的最简单方法,但需要创建一个新的列表,这不是 OP 想要的。(虽然没有太多原因需要在原地操作列表——除非列表非常大,为了性能考虑) - undefined

1

你连接的答案是正确的。按多个值排序的关键在于,次要属性仅在主属性相等时才重要。您的排序比较的伪代码实现可能如下:

compare x and y position
if they differ, return order
else compare name, return order

Sort方法中,跟随(x,y)=>的代码必须返回0,如果项目相等,则返回负数表示第一个应该在第二个之前,返回正数表示第二个应该在第一个之前。基于这些情况和其参数,CompareTo方法将返回-1、0或1。由于需要比较两个不同的属性,因此需要调用两次CompareTo。如果您决定将它们加在一起,您可能会遇到以下情况:
  • x.position < y.position (比较返回-1)
  • x.name > y.name (比较返回1)
  • 结果为0,项目被视为相等,在这种情况下,您的规则明确说明x应该首先出现。
为了解决这个问题,我们需要确保只有当位置相等时才比较名称。由于CompareTo只返回-1、0或1,如果将位置结果乘以2(或任何更大的数字),则只有在位置相等时名称比较才会改变结果。(因为-2+1=-12-1=1
因此,使用你原来链接答案中的方法,你的代码应该是这样的:
list.Sort((x, y) => 
    2 * x.Position.CompareTo(y.Position) 
    + x.Name.CompareTo(y.Name));

@Hamma: 我希望它能帮助你理解为什么存在乘法。你还应该考虑Rene Hilgers的回答。虽然它确实创建了一个新列表,但除非你要进行多次此类排序,并且你的列表相当大并且试图避免垃圾收集,否则你可能不需要担心为此排序创建新列表。 - undefined
1
我正在使用不同的线程通过锁同时访问和修改列表,所以我的关注点是尽快且有效地执行操作。 我理解乘法是为了给这两个属性赋予一个层次结构。 - undefined

0
list = list.OrderBy(item => item.Name).ToList();
list.Sort((x, y) => x.Position.CompareTo(y.Position));

这在隐式地依赖底层排序算法不改变相等项的顺序。 - undefined

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