string[] fruits = { "grape", "passionfruit", "banana", "mango",
"orange", "raspberry", "apple", "blueberry" };
// Sort the strings first by their length and then
//alphabetically by passing the identity selector function.
IEnumerable<string> query =
fruits.OrderBy(fruit => fruit.Length).ThenBy(fruit => fruit);
如果我们需要比一次调用 OrderBy
可能的更多订购,那么我们应该随后调用 ThenBy
而不是 OrderBy,因为排序由 ThenBy
是稳定的,因此保留了具有相同键值的输入元素的顺序。
a) 在上面的例子中 OrderBy
返回 IOrderedEnumerable<>
序列 R 依次为 ThenBy
在这个序列上被调用。当OrderBy
返回 R,R 是否还存储 fruit.Length
使用的键值(OrderBy
值)对 R 中的元素进行排序?
b) R 中的键值存储在哪里?
谢谢
最佳答案
我认为这个问题的答案与你想的不同;
OrderBy
和 ThenBy
是所谓的“延迟运算符”。你所描述的行为在某种程度上是正确的,但实际上不是......
OrderBy
确实返回您建议的类型的引用。但是那个对象不是传统意义上的集合;它是表达式树的一部分。对 ThenBy
的后续调用会进一步修改此表达式树。
所述表达式树实际上可能按照您可能假设的反向顺序进行排序。它甚至可能检测到您每次都尝试进行相同的排序,而不是两者都进行(您在示例代码中没有做过任何此类事情,但我只是在说明一点)。
特别是,执行单个 OrderBy
和 ThenBy
实际上可以通过反向执行这些排序来快速轻松地完成。请记住关于 OrderBy
不确定的说法...
var names = //initialize list of names;
var namesByAlpha = BubbleSort(names=>names);
var namesByAlphaAndLength = BubbleSort(namesByAlpha=>namesByAlpha.Length);
假设 BubbleSort
是一种方法,该方法通过将列表中的每个项目与下一个项目进行比较,并在需要时交换位置(不考虑相同的情况),并重复直到整个列表不再需要交换...这最终会得到与您发布的 LINQ 方法相同的结果...但请注意,它按名称 alpha first 进行排序。当它稍后按长度排序时,它会按照字母顺序保留相同长度的名称,因此 OrderBy
显示长度“首先”,然后按字母顺序。
OrderBy
和 ThenBy
可能不会进行冒泡排序(对于任何可观大小的集合来说,它的效率都非常低),但要了解它们的作用,您需要了解他们正在构建一个表达式树,该树在您枚举集合时执行,并且该表达式树正在考虑整个操作列表。它不仅仅是做一个排序,然后做下一个......每个作为单独的操作。
关于linq - OrderBy、ThenBy 和 IOrderedEnumerable<T>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5860949/