2020-01-23 00:21:03 +00:00
#nullable disable
using System ;
2014-07-03 18:43:49 +00:00
using System.Collections.Generic ;
2020-03-05 00:40:26 +00:00
using System.Linq ;
2014-07-03 18:43:49 +00:00
namespace BizHawk.Common.CollectionExtensions
{
public static class CollectionExtensions
{
2020-03-05 00:40:26 +00:00
public static IOrderedEnumerable < TSource > OrderBy < TSource , TKey > (
this IEnumerable < TSource > source ,
Func < TSource , TKey > keySelector ,
bool desc )
{
return desc ? source . OrderByDescending ( keySelector ) : source . OrderBy ( keySelector ) ;
}
2014-07-03 18:43:49 +00:00
public static int LowerBoundBinarySearch < T , TKey > ( this IList < T > list , Func < T , TKey > keySelector , TKey key ) where TKey : IComparable < TKey >
{
int min = 0 ;
int max = list . Count ;
int mid ;
TKey midKey ;
while ( min < max )
{
mid = ( max + min ) / 2 ;
T midItem = list [ mid ] ;
midKey = keySelector ( midItem ) ;
int comp = midKey . CompareTo ( key ) ;
if ( comp < 0 )
{
min = mid + 1 ;
}
else if ( comp > 0 )
{
max = mid - 1 ;
}
else
{
return mid ;
}
}
2017-04-13 18:57:58 +00:00
// did we find it exactly?
2014-07-03 18:43:49 +00:00
if ( min = = max & & keySelector ( list [ min ] ) . CompareTo ( key ) = = 0 )
{
return min ;
}
mid = min ;
2020-02-25 19:45:45 +00:00
// we didn't find it. return something corresponding to lower_bound semantics
2014-07-03 18:43:49 +00:00
if ( mid = = list . Count )
{
return max ; // had to go all the way to max before giving up; lower bound is max
}
if ( mid = = 0 )
{
return - 1 ; // had to go all the way to min before giving up; lower bound is min
}
midKey = keySelector ( list [ mid ] ) ;
if ( midKey . CompareTo ( key ) > = 0 )
{
return mid - 1 ;
}
return mid ;
}
2019-12-27 19:41:54 +00:00
/// <exception cref="InvalidOperationException"><paramref name="key"/> not found after mapping <paramref name="keySelector"/> over <paramref name="list"/></exception>
/// <remarks>implementation from https://stackoverflow.com/a/1766369/7467292</remarks>
2014-07-03 18:43:49 +00:00
public static T BinarySearch < T , TKey > ( this IList < T > list , Func < T , TKey > keySelector , TKey key )
where TKey : IComparable < TKey >
{
int min = 0 ;
int max = list . Count ;
while ( min < max )
{
int mid = ( max + min ) / 2 ;
T midItem = list [ mid ] ;
TKey midKey = keySelector ( midItem ) ;
int comp = midKey . CompareTo ( key ) ;
if ( comp < 0 )
{
min = mid + 1 ;
}
else if ( comp > 0 )
{
max = mid - 1 ;
}
else
{
return midItem ;
}
}
2017-04-13 18:57:58 +00:00
2014-07-03 18:43:49 +00:00
if ( min = = max & &
keySelector ( list [ min ] ) . CompareTo ( key ) = = 0 )
{
return list [ min ] ;
}
throw new InvalidOperationException ( "Item not found" ) ;
}
}
}