Skip to content

Commit e689ea5

Browse files
committed
MinBy & MaxBy
1 parent 6a18cb4 commit e689ea5

File tree

3 files changed

+161
-1
lines changed

3 files changed

+161
-1
lines changed

.editorconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ csharp_style_var_when_type_is_apparent = true:suggestion
5050
csharp_style_var_elsewhere = false:suggestion
5151
dotnet_diagnostic.CA1001.severity = warning
5252
dotnet_diagnostic.CA1309.severity = warning
53+
dotnet_diagnostic.CA1510.severity = none
5354

5455
[*.{cs,vb}]
5556
#### Naming styles ####

src/Extensions/ReadOnlySpan/ReadOnlySpanExtensions.Linq.cs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
24
using System.Numerics;
35

46
namespace SpanExtensions
@@ -1920,5 +1922,162 @@ public static BigInteger Max<T>(this ReadOnlySpan<T> source, Func<T, BigInteger>
19201922
return max;
19211923
}
19221924
#endif
1925+
1926+
/// <summary>
1927+
/// Returns the minimum value in a generic sequence according to a specified key selector function.
1928+
/// </summary>
1929+
/// <typeparam name="TSource">The type of elements in <paramref name="source"/>.</typeparam>
1930+
/// <typeparam name="TKey">The type of key to compare elements by.</typeparam>
1931+
/// <param name="source">A <see cref="ReadOnlySpan{TSource}"/> to determine the minimum value of.</param>
1932+
/// <param name="keySelector">A function to extract the key for each element.</param>
1933+
/// <returns>The value with the minimum key in <paramref name="source"/>.</returns>
1934+
/// <exception cref="ArgumentNullException"><paramref name="keySelector"/> is null.</exception>
1935+
/// <exception cref="InvalidOperationException"><typeparamref name="TSource"/> is a primitive type and <paramref name="source"/> is empty.</exception>
1936+
/// <remarks>If <paramref name="source"/> is empty and <typeparamref name="TSource"/> is a non-nullable struct, such as a primitive type, an <see cref="InvalidOperationException"/> is thrown.</remarks>
1937+
public static TSource MinBy<TSource, TKey>(this ReadOnlySpan<TSource> source, Func<TSource, TKey> keySelector) where TKey : IComparable<TKey>
1938+
{
1939+
if(keySelector is null)
1940+
{
1941+
throw new ArgumentNullException(nameof(keySelector));
1942+
}
1943+
if(source.IsEmpty)
1944+
{
1945+
throw new InvalidOperationException($"{nameof(source)} is empty");
1946+
}
1947+
1948+
TSource min = source[0];
1949+
TKey minKey = keySelector(min);
1950+
for(int i = 1; i < source.Length; i++)
1951+
{
1952+
TSource value = source[i];
1953+
TKey current = keySelector(value);
1954+
if(current.CompareTo(minKey) < 0)
1955+
{
1956+
min = value;
1957+
minKey = current;
1958+
}
1959+
}
1960+
return min;
1961+
}
1962+
1963+
/// <summary>
1964+
/// Returns the minimum value in a generic sequence according to a specified key selector function.
1965+
/// </summary>
1966+
/// <typeparam name="TSource">The type of elements in <paramref name="source"/>.</typeparam>
1967+
/// <typeparam name="TKey">The type of key to compare elements by.</typeparam>
1968+
/// <param name="source">A <see cref="ReadOnlySpan{TSource}"/> to determine the minimum value of.</param>
1969+
/// <param name="keySelector">A function to extract the key for each element.</param>
1970+
/// <param name="comparer">The <see cref="IComparer{TSource}"/> to compare keys.</param>
1971+
/// <returns>The value with the minimum key in <paramref name="source"/>.</returns>
1972+
/// <exception cref="ArgumentNullException"><paramref name="keySelector"/> is null.</exception>
1973+
/// <exception cref="InvalidOperationException"><typeparamref name="TSource"/> is a primitive type and <paramref name="source"/> is empty.</exception>
1974+
/// <remarks>If <paramref name="source"/> is empty and <typeparamref name="TSource"/> is a non-nullable struct, such as a primitive type, an <see cref="InvalidOperationException"/> is thrown.</remarks>
1975+
public static TSource MinBy<TSource, TKey>(this ReadOnlySpan<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
1976+
{
1977+
if(keySelector is null)
1978+
{
1979+
throw new ArgumentNullException(nameof(keySelector));
1980+
}
1981+
if(comparer is null)
1982+
{
1983+
throw new ArgumentNullException(nameof(comparer));
1984+
}
1985+
if(source.IsEmpty)
1986+
{
1987+
throw new InvalidOperationException($"{nameof(source)} is empty");
1988+
}
1989+
1990+
TSource min = source[0];
1991+
TKey minKey = keySelector(min);
1992+
for(int i = 1; i < source.Length; i++)
1993+
{
1994+
TSource value = source[i];
1995+
TKey current = keySelector(value);
1996+
if(comparer.Compare(current, minKey) < 0)
1997+
{
1998+
min = value;
1999+
minKey = current;
2000+
}
2001+
}
2002+
return min;
2003+
}
2004+
2005+
/// <summary>
2006+
/// Returns the maximum value in a generic sequence according to a specified key selector function.
2007+
/// </summary>
2008+
/// <typeparam name="TSource">The type of elements in <paramref name="source"/>.</typeparam>
2009+
/// <typeparam name="TKey">The type of key to compare elements by.</typeparam>
2010+
/// <param name="source">A <see cref="ReadOnlySpan{TSource}"/> to determine the maximum value of.</param>
2011+
/// <param name="keySelector">A function to extract the key for each element.</param>
2012+
/// <returns>The value with the maximum key in <paramref name="source"/>.</returns>
2013+
/// <exception cref="ArgumentNullException"><paramref name="keySelector"/> is null.</exception>
2014+
/// <exception cref="InvalidOperationException"><typeparamref name="TSource"/> is a primitive type and <paramref name="source"/> is empty.</exception>
2015+
/// <remarks>If <paramref name="source"/> is empty and <typeparamref name="TSource"/> is a non-nullable struct, such as a primitive type, an <see cref="InvalidOperationException"/> is thrown.</remarks>
2016+
public static TSource MaxBy<TSource, TKey>(this ReadOnlySpan<TSource> source, Func<TSource, TKey> keySelector) where TKey : IComparable<TKey>
2017+
{
2018+
if(keySelector is null)
2019+
{
2020+
throw new ArgumentNullException(nameof(keySelector));
2021+
}
2022+
if(source.IsEmpty)
2023+
{
2024+
throw new InvalidOperationException($"{nameof(source)} is empty");
2025+
}
2026+
TSource max = source[0];
2027+
TKey maxKey = keySelector(max);
2028+
for(int i = 1; i < source.Length; i++)
2029+
{
2030+
TSource value = source[i];
2031+
TKey current = keySelector(value);
2032+
if(current.CompareTo(maxKey) > 0)
2033+
{
2034+
max = value;
2035+
maxKey = current;
2036+
}
2037+
}
2038+
return max;
2039+
}
2040+
2041+
/// <summary>
2042+
/// Returns the maximum value in a generic sequence according to a specified key selector function.
2043+
/// </summary>
2044+
/// <typeparam name="TSource">The type of elements in <paramref name="source"/>.</typeparam>
2045+
/// <typeparam name="TKey">The type of key to compare elements by.</typeparam>
2046+
/// <param name="source">A <see cref="ReadOnlySpan{TSource}"/> to determine the maximum value of.</param>
2047+
/// <param name="keySelector">A function to extract the key for each element.</param>
2048+
/// <param name="comparer">The <see cref="IComparer{TSource}"/> to compare keys.</param>
2049+
/// <returns>The value with the maximum key in <paramref name="source"/>.</returns>
2050+
/// <exception cref="ArgumentNullException"><paramref name="keySelector"/> is null.</exception>
2051+
/// <exception cref="InvalidOperationException"><typeparamref name="TSource"/> is a primitive type and <paramref name="source"/> is empty.</exception>
2052+
/// <remarks>If <paramref name="source"/> is empty and <typeparamref name="TSource"/> is a non-nullable struct, such as a primitive type, an <see cref="InvalidOperationException"/> is thrown.</remarks>
2053+
public static TSource MaxBy<TSource, TKey>(this ReadOnlySpan<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
2054+
{
2055+
if(keySelector is null)
2056+
{
2057+
throw new ArgumentNullException(nameof(keySelector));
2058+
}
2059+
if(comparer is null)
2060+
{
2061+
throw new ArgumentNullException(nameof(comparer));
2062+
}
2063+
if(source.IsEmpty)
2064+
{
2065+
throw new InvalidOperationException($"{nameof(source)} is empty");
2066+
}
2067+
2068+
TSource max = source[0];
2069+
TKey maxKey = keySelector(max);
2070+
for(int i = 1; i < source.Length; i++)
2071+
{
2072+
TSource value = source[i];
2073+
TKey current = keySelector(value);
2074+
if(comparer.Compare(current, maxKey) > 0)
2075+
{
2076+
max = value;
2077+
maxKey = current;
2078+
}
2079+
}
2080+
return max;
2081+
}
19232082
}
19242083
}

src/Extensions/Span/SpanExtensions.Linq.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -820,7 +820,7 @@ public static Half Max(this Span<Half> source)
820820
{
821821
return ReadOnlySpanExtensions.Max(source);
822822
}
823-
823+
824824
/// <summary>
825825
/// Invokes a transform function on each element in <paramref name="source"/> and returns the maximum resulting value.
826826
/// </summary>

0 commit comments

Comments
 (0)