An open API service indexing awesome lists of open source software.

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.

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);
```