-
-
Notifications
You must be signed in to change notification settings - Fork 9
/
Rank.cs
160 lines (152 loc) · 5.34 KB
/
Rank.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
namespace SuperLinq;
public static partial class SuperEnumerable
{
/// <summary>
/// Ranks each item in the sequence in ascending order using a default comparer. The rank is equal to
/// index + 1 of the first element of the item's equality set.
/// </summary>
/// <typeparam name="TSource">
/// Type of item in the sequence
/// </typeparam>
/// <param name="source">
/// The sequence whose items will be ranked
/// </param>
/// <returns>
/// A sorted sequence of items and their rank.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="source"/> is <see langword="null"/>.
/// </exception>
/// <remarks>
/// <para>
/// This method is implemented by using deferred execution. However, <paramref name="source"/> will be consumed
/// in it's entirety immediately when first element of the returned sequence is consumed.
/// </para>
/// </remarks>
public static IEnumerable<(TSource item, int rank)> Rank<TSource>(
this IEnumerable<TSource> source)
{
return source.RankBy(Identity);
}
/// <summary>
/// Ranks each item in the sequence in ascending order using a caller-supplied comparer. The rank is equal to
/// index + 1 of the first element of the item's equality set.
/// </summary>
/// <typeparam name="TSource">
/// The type of the elements in the source sequence
/// </typeparam>
/// <param name="source">
/// The sequence of items to rank
/// </param>
/// <param name="comparer">
/// A object that defines comparison semantics for the elements in the sequence
/// </param>
/// <returns>
/// A sorted sequence of items and their rank.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="source"/> is <see langword="null"/>.
/// </exception>
/// <remarks>
/// <para>
/// This method is implemented by using deferred execution. However, <paramref name="source"/> will be consumed
/// in it's entirety immediately when first element of the returned sequence is consumed.
/// </para>
/// </remarks>
public static IEnumerable<(TSource item, int rank)> Rank<TSource>(
this IEnumerable<TSource> source, IComparer<TSource> comparer)
{
return source.RankBy(Identity, comparer);
}
/// <summary>
/// Ranks each item in the sequence in the order defined by <paramref name="sortDirection"/> using a default
/// comparer. The rank is equal to index + 1 of the first element of the item's equality set.
/// </summary>
/// <typeparam name="TSource">
/// Type of item in the sequence
/// </typeparam>
/// <param name="source">
/// The sequence whose items will be ranked
/// </param>
/// <param name="sortDirection">
/// Defines the ordering direction for the sequence
/// </param>
/// <returns>
/// A sorted sequence of items and their rank.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="source"/> is <see langword="null"/>.
/// </exception>
/// <remarks>
/// <para>
/// This method is implemented by using deferred execution. However, <paramref name="source"/> will be consumed
/// in it's entirety immediately when first element of the returned sequence is consumed.
/// </para>
/// </remarks>
public static IEnumerable<(TSource item, int rank)> Rank<TSource>(
this IEnumerable<TSource> source, OrderByDirection sortDirection)
{
return source.RankBy(Identity, sortDirection);
}
/// <summary>
/// Ranks each item in the sequence in the order defined by <paramref name="sortDirection"/> using a
/// caller-supplied comparer. The rank is equal to index + 1 of the first element of the item's equality set.
/// </summary>
/// <typeparam name="TSource">
/// The type of the elements in the source sequence
/// </typeparam>
/// <param name="source">
/// The sequence of items to rank
/// </param>
/// <param name="comparer">
/// A object that defines comparison semantics for the elements in the sequence
/// </param>
/// <param name="sortDirection">
/// Defines the ordering direction for the sequence
/// </param>
/// <returns>
/// A sorted sequence of items and their rank.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="source"/> is <see langword="null"/>.
/// </exception>
/// <remarks>
/// <para>
/// This method is implemented by using deferred execution. However, <paramref name="source"/> will be consumed
/// in it's entirety immediately when first element of the returned sequence is consumed.
/// </para>
/// </remarks>
public static IEnumerable<(TSource item, int rank)> Rank<TSource>(
this IEnumerable<TSource> source,
IComparer<TSource> comparer,
OrderByDirection sortDirection)
{
return source.RankBy(Identity, comparer, sortDirection);
}
private static IEnumerable<(TSource, int)> RankCore<TSource, TKey>(
IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IComparer<TKey>? comparer,
bool isDense,
OrderByDirection sortDirection = OrderByDirection.Ascending)
{
comparer ??= Comparer<TKey>.Default;
var rank = 0;
var count = 1;
foreach (var (cur, lag) in source
.OrderBy(keySelector, comparer, sortDirection)
.Lag(1))
{
if (rank == 0
|| comparer.Compare(
keySelector(cur),
keySelector(Debug.AssertNotNull(lag))) != 0)
{
rank += isDense ? 1 : count;
count = 0;
}
count++;
yield return (cur, rank);
}
}
}