我想从列表中进行排名并按原始顺序输出.
到目前为止这是我的代码:
var data = new[] { 7.806468478, 7.806468478, 7.806468478, 7.173501754, 7.173501754, 7.173501754, 3.40877696, 3.40877696, 3.40877696, 4.097010736, 4.097010736, 4.097010736, 4.036494085, 4.036494085, 4.036494085, 38.94333318, 38.94333318, 38.94333318, 14.43588131, 14.43588131, 14.43588131 }; var rankings = data.OrderByDescending(x => x) .GroupBy(x => x) .SelectMany((g, i) => g.Select(e => new { Col1 = e, Rank = i + 1 })) .ToList();
但是,结果将从降序开始:
我想要的是按原始顺序显示.
例如:Rank = 3,Rank = 3,Rank = 3,Rank = 4,Rank = 4,Rank = 4等...
谢谢.
使用你拥有的,一种方法是跟踪原始顺序并再次排序(丑陋且可能很慢):
var rankings = data.Select((x, i) => new {Item = x, Index = i}) .OrderByDescending(x => x.Item) .GroupBy(x => x.Item) .SelectMany((g, i) => g.Select(e => new { Index = e.Index, Item = new { Col1 = e.Item, Rank = i + 1 } })) .OrderBy(x => x.Index) .Select(x => x.Item) .ToList();
我建议你建议用你的排名创建一个字典,并将其与你的列表一起加入:
var rankings = data.Distinct() .OrderByDescending(x => x) .Select((g, i) => new { Key = g, Rank = i + 1 }) .ToDictionary(x => x.Key, x => x.Rank); var output = data.Select(x => new { Col1 = x, Rank = rankings[x] }) .ToList();
正如@AntonínLejsek所指出的那样,取代上述GroupBy
呼叫Distinct()
是要走的路.
注意double
s不是精确类型,因此实际上不是查找表中值的良好候选者,我也不建议使用GroupBy
/ Distinct
将浮点值作为键.请注意您的精确度并考虑使用适当的字符串转换.鉴于此,您可能希望定义一个epsilon值并GroupBy
完全放弃LINQ ,而是选择将每个数据点封装到(非匿名)引用类型中,然后遍历排序列表并分配排名.例如(免责声明:未经测试):
class DataPoint { decimal Value { get; set; } int Rank { get; set; } } var dataPointsPreservingOrder = data.Select(x => new DataPoint {Value = x}).ToList(); var sortedDescending = dataPointsPreservingOrder.OrderByDescending(x => x.Value).ToList(); var epsilon = 1E-15; //use a value that makes sense here int rank = 0; double? currentValue = null; foreach(var x in sortedDescending) { if(currentValue == null || Math.Abs(x.Value - currentValue.Value) > epsilon) { currentValue = x.Value; ++rank; } x.Rank = rank; }