https://github.com/nenonaninu/nthitemutils
Script to get the nth smallest/largest item. Inspired by std::nth_element.
https://github.com/nenonaninu/nthitemutils
csharp nthelement quickselect
Last synced: 7 months ago
JSON representation
Script to get the nth smallest/largest item. Inspired by std::nth_element.
- Host: GitHub
- URL: https://github.com/nenonaninu/nthitemutils
- Owner: nenoNaninu
- License: mit
- Created: 2020-08-26T14:43:39.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2020-08-29T17:29:57.000Z (almost 6 years ago)
- Last Synced: 2025-01-07T12:37:39.613Z (over 1 year ago)
- Topics: csharp, nthelement, quickselect
- Language: C#
- Homepage:
- Size: 25.4 KB
- Stars: 2
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# NthItemUtils
A library for getting the nth smallest value, the nth largest value, etc. from a randomly accessible data structure like `Span`,`ReadOnlySpan`, `IReadOnlyList`.
Internally, it uses QuickSelect as well as C++ `std::nth_element()`, so the average performance is O(n).
The source code consists of **only one file**, so you can easily use it by copy and past.
[source code](https://github.com/nenoNaninu/NthItemUtils/blob/master/NthItemUtils/NthItemUtils.cs)
or [nuget](https://www.nuget.org/packages/NthItemUtils/).
```
dotnet add package NthItemUtils
```
# API
API is defined as an extension method of `Span`, `ReadOnlySpan`, and `IReadOnlyList`.
The range of n is between 0 and source.Length - 1.
All return value types are `struct ItemWithIndex{ T Item; int index }`.
```cs
NthSmallest(this Span source, int n)
NthSmallest(this Span source, int n, Comparer comparer)
NthLargest(this Span source, int n)
NthLargest(this Span source, int n, Comparer comparer)
MaxWithIndex(this Span source)
MaxWithIndex(this Span source, Comparer comparer)
MinWithIndex(this Span source)
MinWithIndex(this Span source, Comparer comparer)
```
Since QuickSelect is used internally, this is also published as an API.
```cs
public static class QuickSelect
{
public static void Iota(Span indices);
public static void Execute(ReadOnlySpan source, Span indices, int n);
public static void Execute(ReadOnlySpan source, Span indices, int n, Comparer comparer);
public static void Execute(IReadOnlyList source, Span indices, int n);
public static void Execute(IReadOnlyList source, Span indices, int n, Comparer comparer);
}
```
# Example
Extension Method.
```cs
var random = new Random();
var randomSource = Enumerable.Range(0, 200).Select(_ => random.NextDouble() * 50).ToArray();
var order = randomSource.OrderBy(x => x).ToArray();
int n = random.Next(200);
Assert.IsTrue(order[n] == randomSource.AsSpan().NthSmallest(n).Item); // always true.
```
QuickSelect
```cs
ReadOnlySpan source = new int[] { 4, 4, 8, 1, 2, 5, 4, 4, 4, 6, 7, 3 }.AsSpan();
var pool = ArrayPool.Shared.Rent(source.Length);
var indices = pool.AsSpan(0, source.Length);
int n = 6;
QuickSelect.Iota(indices);
QuickSelect.Execute(source, indices, n);
var pivot = source[indices[n]];
for (int i = 0; i < n; i++)
{
var result = Comparer.Default.Compare(source[indices[i]], pivot);
Assert.IsTrue(result <= 0); // always true.
}
for (int i = n + 1; i < source.Length; i++)
{
var result = Comparer.Default.Compare(source[indices[i]], pivot);
Assert.IsTrue(0 <= result); // always true.
}
ArrayPool.Shared.Return(pool);
```
Get items in some range
```cs
ReadOnlySpan randomSource = Enumerable.Range(0, 100).Shuffle().ToArray().AsSpan();
var pool = ArrayPool.Shared.Rent(randomSource.Length);
var indices = pool.AsSpan(0, randomSource.Length);
QuickSelect.Iota(indices);
//Get 50 <= item < 60
QuickSelect.Execute(randomSource, indices, 50);
QuickSelect.Execute(randomSource, indices[50..], 10);
for (int i = 0; i < 10; i++)
{
Console.Write($"{randomSource[indices[50 + i]]}, ");
}
// output : 50, 56, 51, 57, 55, 54, 53, 52, 58, 59,
ArrayPool.Shared.Return(pool);
```