From 08e3e34162cf7fa73dcd877f8cd48d7dfd80baa5 Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Wed, 5 Apr 2023 13:35:54 +0500 Subject: [PATCH] Add BinarySearch extension for Span --- AsbCloudInfrastructure/DateTimeExtentions.cs | 39 ++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/AsbCloudInfrastructure/DateTimeExtentions.cs b/AsbCloudInfrastructure/DateTimeExtentions.cs index 181740a5..01a994b9 100644 --- a/AsbCloudInfrastructure/DateTimeExtentions.cs +++ b/AsbCloudInfrastructure/DateTimeExtentions.cs @@ -37,5 +37,44 @@ namespace AsbCloudInfrastructure var dateTz = date.ToOffset(TimeSpan.FromHours(remoteTimezoneOffsetHours)); return dateTz.DateTime; } + + /// + /// Поиск индекса близкого к value значения в span. + /// Элементы в span должны быть отсортированы по возрастанию по полю propertyGetter. + /// + /// + /// + /// + /// метод получения свойства из объекта класса T + /// искомое значение + /// максимальное кол-во итераций. Прим.: + /// в span из 4000 записей достаточно 9-ти итераций + /// 8_000 => 10 итераций; + /// 16_000 => 11; + /// ... + /// 256_000 => 15; + /// При недостаточном кол-ве итераций индекс может оказаться близко, но это будет не ближайшее значение + /// + /// + public static int BinarySearch(this Span span, Func propertyGetter, TProp value, int maxIterations = 16) + where TProp : IComparable + { + if (span.Length < 2 || --maxIterations < 0) + return 0; + + var indexOfMiddle = span.Length >> 1; + + var comparison = value.CompareTo(propertyGetter(span[indexOfMiddle])); + + if (comparison > 0) + { + var index = indexOfMiddle + 1 + BinarySearch(span[(indexOfMiddle + 1)..], propertyGetter, value, maxIterations); + return index < span.Length ? index : span.Length - 1; + } + else if (comparison < 0) + return BinarySearch(span[..(indexOfMiddle)], propertyGetter, value, maxIterations); + else //if (comparison == 0) + return indexOfMiddle; + } } }