如何使用C#获取列表中多个数字的排名列表?

how to get the rank list of multiple number in a list using C#?

我在 C# 中有以下列表:

List<double> arr = new List<double> { 5, 10, 7, 15, 9, 21, 1 };

我想将他们的排名存储在另一个列表中,例如 List<double> rank。最后我想得到以下内容:

6 3 5 2 4 1 7

我该怎么做?

如果all arr中的项目是distinct,你可以创建一个dictionary :

  List<double> arr = new List<double> { 5, 10, 7, 15, 9, 21, 1 };

  var ranks = arr
    .OrderByDescending(item => item)
    .Select((item, index) => new {
      item = item,
      rank = index + 1,
    })
    .ToDictionary(x => x.item, x => x.rank);

然后使用ranks找出对应等级的项目:

    int rankOf5 = ranks[5]; // 6

测试

   string test = string.Join(" ", arr.Select(x => ranks[x]));

   // 6  3  5  2  4  1  7
   Console.Write(test);

编辑:用循环测试:

   foreach (var item in arr)
     Console.Write(ranks[item]);

   for (int i = 0; i < arr.Count; ++i)
      Console.Write(ranks[arr[i]]); 

编辑 2 如果 arr 可以 有重复项,例如

// 21 appears 2 times
List<double> arr = new List<double> { 5, 10, 7, 15, 9, 21, 21, 1 };

您可能想要计算所谓的 密集排名

var ranks = arr
  .GroupBy(item => item)
  .OrderByDescending(chunk => chunk.Key)
  .Select((chunk, index) => new {
     item = chunk.Key,
     rank = index + 1
   })
  .ToDictionary(x => x.item, x => x.rank);

   string test = string.Join(" ", arr.Select(x => ranks[x]));

   // 6 3 5 2 4 1 1 7
   Console.Write(test);

可能最短的方法是在排序列表后使用 IndexOf:

List<double> arr = new List<double> { 5, 10, 7, 15, 9, 21, 1 };
var ranking = arr.OrderByDescending(item => item)
                 .Select(item => arr.IndexOf(item)+1)
                 .ToList();

//Output: 6, 2, 5, 2, 4, 1, 7

或者只是玩 OrderBySelect:

var ranking = arr.Select((item, index) => new { Item = item, Index = index })
                 .OrderByDescending(item => item.Item)
                 .Select((item, index) => new { Item = item.Item, OriginalIndex = item.Index, Rank = ++index })
                 .OrderBy(item => item.OriginalIndex)
                 .Select(item => item.Rank)
                 .ToList();

//Output: 6, 2, 5, 2, 4, 1, 7
List<double> arr = new List<double> { 5, 10, 7, 15, 9, 21, 1 };

var rankDict = arr.Distinct().OrderByDescending(num=>num)
    .Select((number, index) => new {Number = number, Rank = index})
    .ToDictionary(m => m.Number, m => m.Rank);

var rankedArray = new List<double>();

foreach(var num in arr)
{
    rankedArray.Add(rankDict[num] + 1);
}

Console.WriteLine(string.Join("-", rankedArray));

Fiddle - https://dotnetfiddle.net/7C5o52