I believe that there is no simple LINQ equivalent of NTILE(n)
. Anyway, depending on your needs it's not that hard to write one.
The T-SQL documentation says
Distributes the rows in an ordered partition into a specified number of groups. The groups are numbered, starting at one. For each row, NTILE returns the number of the group to which the row belongs.
(see here)
For a very crude implementation of NTILE
you can use GroupBy
. The following example uses an int[]
for sake of simplicity, but of course you are not restricted to
int n = 4;
int[] data = { 5, 2, 8, 2, 3, 8, 3, 2, 9, 5 };
var ntile = data.OrderBy(value => value)
.Select((value,index) => new {Value = value, Index = index})
.GroupBy(c => Math.Floor(c.Index / (data.Count() / (double)n)), c => c.Value);
First, our data
is ordered ascending by it's values. If you are not using simple int
s this could be something like store => store.Revenue
(given you'd like to get the quantiles by revenue of the stores). Futhermore we are selecting the ordered data to an anonymous type, to include the indices. This is necessary since the indices are necessary for grouping, but it seems as GroupBy
does not support lambdas with indices, as Select
does.
The third line is a bit less intuitive, but I'll try and explain: The NTILE
function assigns groups, the rows are assigned to. To create n
groups, we devide N
(number of items) by n
to get the items per group and then device the current index by that, to determine in which group the current item is. To get the number of groups right I had to make the number of items per group fractional and floor the calculated group number, but admittedly, this is rather empirical.
ntile
will contain n
groups, each one having Key
equal to the group number. Each group is enumerable. If you'd like to determine, if an element is in the second quartile, you can check if groups.Where(g => g.Key == 1)
contains the element.
Remarks: The method I've used to determine the group may need some fine adjustment.