-1

Question: I have a list of list number (List<List<int>> listNumberCollection): 4 rows x 3 columns

1 3 9
6 5 6
3 2 7
2 7 2

How can I record of rank in column (smallest number is the 1st) so it should be:

1 2 4
4 3 2
3 1 3
2 4 1

My work: To order numbers in a column, I write a function for transposition (4 columns x 3 rows):

1 6 3 2
3 5 2 7
9 6 7 2

private List<List<Double>> MatrixTransposition(int k, List<List<Double>> listNumberCollection)
{
      var revisedAllRanks = new List<List<Double>>();
      for (int i = 0; i < k; i++ )
      {
           var allRanks = new List<Double>();
           allRanks.AddRange(listNumberCollection.Select(value => value[i]));
           revisedAllRanks.Add(allRanks);
      }
      return revisedAllRanks;
}

I tried to create a class named NumberRank with 2 properties (Number, Rank) and add into list of NumberRank

var revisedListNumberCollection = MatrixTransposition(k, listNumberCollection);
var listNumberRanks = new List<List<NumberRank>>();
foreach(List<Double> vectorsCollection in revisedListNumberCollection)
{                    
     List<NumberRank> numberRanks = vectorsCollection.OrderByDescending(number => number).Select((number, i) => new NumberRank(number, i + 1)).ToList();                        
     listNumberRanks.Add(numberRanks);
}

However, the result I get is ordered number with rank (first column: 1-1 2-2 3-3 6-4...), not what I want (1-1 6-4 3-3 2-2) Thanks!

4

2 回答 2

1

使用纯 Linq 可以轻松完成

var input = new List<List<int>>() {
    new List<int> { 1, 6, 3, 2 },
    new List<int> { 3, 5, 2, 7 },
    new List<int> { 9, 6, 7, 2 }
};

var result = input.Select(l =>
        l.Select((x, i) => new { x = x, i = i}) // selecting index
         .OrderBy(z => z.x) // sorting by value
         .Select((z, j) => new { i = z.i, j = j + 1 }) // selecting rank
         .OrderBy(z => z.i) // sorting by initial index
         .Select(z => z.j)  // returning rank
         .ToList()
     ).ToList();

// List<List<int>>(3)
// {
//    List<int>(4) { 1, 4, 3, 2 },
//    List<int>(4) { 2, 3, 1, 4 },
//    List<int>(4) { 4, 2, 3, 1 } 
//}

更新要将行转置为列并返回,您可以执行以下操作:

var transp_input = Enumerable.Range(0, input[0].Count)
                             .Select(i => input.Select(x => x[i]));

然后你做计算

var transp_result = transp_input.Select(l =>
        l.Select((x, i) => new { x = x, i = i }) // selecting index
         .OrderBy(z => z.x) // sorting by value
         .Select((z, j) => new { i = z.i, j = j + 1 }) // selecting rank
         .OrderBy(z => z.i) // sorting by initial index
         .Select(z => z.j)  // returning rank
         .ToList()
     ).ToList();

并转回

var result = Enumerable.Range(0, transp_result[0].Count)
                       .Select(i => transp_result.Select(x => x[i]).ToList()).ToList();
于 2013-08-11T19:48:54.910 回答
0

我会选择以下内容:

var input = new List<List<int>>() {
    new List<int> { 1, 6, 3, 2 },
    new List<int> { 3, 5, 2, 7 },
    new List<int> { 9, 6, 7, 2 }
};

var results = new List<List<int>>(input.Count);
foreach (var list in input)
{
    var rankDict = list.OrderBy(x => x).Select((v, i) => new { v, i }).ToDictionary(x => x.v, x => x.i);
    results.Add(list.Select(x => rankDict[x] + 1).ToList());
}

foreach (var list in results)
{
    Console.WriteLine(string.Join(" ", list.Select(x => x.ToString())));
}

它不是纯 LINQ,而是做你期望的。结果是:

1 4 3 2
2 3 1 4
4 2 3 1

但是,它有一个限制:它要求单个列表值是唯一的。

于 2013-08-11T12:48:32.210 回答