Position ranking solution in my LIST?

Given the following code:

class Results { public int playerId; public int score; public int section; public int position; public Results(int _playerId, int _score, int _section) { playerId = _playerId; score = _score; section = _section; } } public void RankMyResults() { List<Results> myResultList = new List<Results>(); myResultList.Add(new Results(1,232, 1)); myResultList.Add(new Results(2,213, 1)); // Add a lot of more results // Iteriate over the items to set the position } 

I want to set position 1 for the highest score in each section, position 2 for the second highest and so on.

Also, if two people have the same score, the position should look like this:

 Position Score PlayerId Section 1 135 23 1 1 135 43 1 3 131 45 1 

As in this example, he will skip position 2.

Is there a good way to use LINQ for this or, for example, using some Select, Sorting functions from a List object?

My own list iteration decision is bad!

+4
source share
2 answers

I wrote these extension methods just a few days ago:

  #region RankBy public static IEnumerable<TResult> RankBy<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, int, TResult> resultSelector) { return source.RankBy(keySelector, null, false, resultSelector); } public static IEnumerable<TResult> RankBy<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer, Func<TSource, int, TResult> resultSelector) { return source.RankBy(keySelector, comparer, false, resultSelector); } public static IEnumerable<TResult> RankByDescending<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer, Func<TSource, int, TResult> resultSelector) { return source.RankBy(keySelector, comparer, true, resultSelector); } public static IEnumerable<TResult> RankByDescending<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, int, TResult> resultSelector) { return source.RankBy(keySelector, null, true, resultSelector); } private static IEnumerable<TResult> RankBy<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer, bool descending, Func<TSource, int, TResult> resultSelector) { comparer = comparer ?? Comparer<TKey>.Default; var grouped = source.GroupBy(keySelector); var ordered = descending ? grouped.OrderByDescending(g => g.Key, comparer) : grouped.OrderBy(g => g.Key, comparer); int totalRank = 1; foreach (var group in ordered) { int rank = totalRank; foreach (var item in group) { yield return resultSelector(item, rank); totalRank++; } } } #endregion #region DenseRankBy public static IEnumerable<TResult> DenseRankBy<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, int, TResult> resultSelector) { return source.DenseRankBy(keySelector, null, false, resultSelector); } public static IEnumerable<TResult> DenseRankBy<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer, Func<TSource, int, TResult> resultSelector) { return source.DenseRankBy(keySelector, comparer, false, resultSelector); } public static IEnumerable<TResult> DenseRankByDescending<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer, Func<TSource, int, TResult> resultSelector) { return source.DenseRankBy(keySelector, comparer, true, resultSelector); } public static IEnumerable<TResult> DenseRankByDescending<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, int, TResult> resultSelector) { return source.DenseRankBy(keySelector, null, true, resultSelector); } private static IEnumerable<TResult> DenseRankBy<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer, bool descending, Func<TSource, int, TResult> resultSelector) { comparer = comparer ?? Comparer<TKey>.Default; var grouped = source.GroupBy(keySelector); var ordered = descending ? grouped.OrderByDescending(g => g.Key, comparer) : grouped.OrderBy(g => g.Key, comparer); int rank = 1; foreach (var group in ordered) { foreach (var item in group) { yield return resultSelector(item, rank); } rank++; } } #endregion 

You can use them as follows:

 var rankedPlayers = players.RankByDescending( p => p.Score, (p, r) => new { Rank = r, Player = p }); 

The difference between RankBy and DenseRankBy is that RankBy creates β€œspaces” (for example, 1,1,3,3,3,6 ...), whereas DenseRankBy does not (1,1, 2,2,2,3 ...)

+8
source

I modified these great methods above to keep the original order. The ranking methods should not change the order of the elements, they should simply rank them and return the elements in the original input order of the collection.

 private static IEnumerable<TResult> RankBy<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer, bool descending, Func<TSource, int, TResult> resultSelector) { var comp0 = comparer ?? Comparer<TKey>.Default; var comp = descending ? Comparer<TKey>.Create((x, y) => -comp0.Compare(x, y)) : comp0; var keys = source.Select(x => keySelector(x)).ToArray(); var indexes = Enumerable.Range(0, keys.Length).ToArray(); Array.Sort<TKey, int>(keys, indexes, comp); var groups = new int[keys.Length]; int group = 0; int index = 0; for (int j = 1; j < keys.Length; ++j) { ++index; if (comp.Compare(keys[j], keys[j - 1]) != 0) { group += index; index = 0; } groups[indexes[j]] = group; } index = 0; foreach (var item in source) { yield return resultSelector(item, groups[index++] + 1); } } private static IEnumerable<TResult> DenseRankBy<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer, bool descending, Func<TSource, int, TResult> resultSelector) { var comp0 = comparer ?? Comparer<TKey>.Default; var comp = descending ? Comparer<TKey>.Create((x, y) => -comp0.Compare(x, y)) : comp0; var keys = source.Select(x => keySelector(x)).ToArray(); var indexes = Enumerable.Range(0, keys.Length).ToArray(); Array.Sort<TKey, int>(keys, indexes, comp); var groups = new int[keys.Length]; int group = 0; for (int j = 1; j < keys.Length; ++j) { if (comp.Compare(keys[j], keys[j - 1]) != 0) ++group; groups[indexes[j]] = group; } int index = 0; foreach (var item in source) { yield return resultSelector(item, groups[index++] + 1); } } 
0
source

Source: https://habr.com/ru/post/1380611/


All Articles