public static int BinarySearchIndex <T>( this IList <T> sortedList, T key, BinarySearchMethod method = BinarySearchMethod.Exact, int lowerBoundIndex = 0, int upperBoundIndex = -1, IComparer <T> comparer = null) { if (sortedList == null) { throw new ArgumentNullException("sortedList"); } if (comparer == null) { comparer = Comparer <T> .Default; } int count = sortedList.Count; if (lowerBoundIndex < 0 || lowerBoundIndex > count || (count > 0 && lowerBoundIndex == count)) { throw new ArgumentOutOfRangeException( "lowerBoundIndex", lowerBoundIndex, string.Format(LowerBoundOutOfRangeMsg, count) ); } if (upperBoundIndex < 0) { upperBoundIndex = count + upperBoundIndex; } if ((count > 0 && (upperBoundIndex == count || upperBoundIndex < lowerBoundIndex)) || upperBoundIndex > count) { throw new ArgumentOutOfRangeException( "upperBoundIndex", upperBoundIndex, string.Format(UpperBoundOutOfRangeMsg, lowerBoundIndex, count) ); } if (count == 0) { return(-1); } bool isFirst = (method & BinarySearchMethod.FirstExact) == BinarySearchMethod.FirstExact; bool isLast = (method & BinarySearchMethod.LastExact) == BinarySearchMethod.LastExact; while (lowerBoundIndex <= upperBoundIndex) { int middleIndex = lowerBoundIndex + (upperBoundIndex - lowerBoundIndex) / 2; int comparison = comparer.Compare(sortedList[middleIndex], key); if (comparison < 0) { lowerBoundIndex = middleIndex + 1; } else if (comparison > 0) { upperBoundIndex = middleIndex - 1; } else if (upperBoundIndex - lowerBoundIndex < 2) { if (isFirst && comparer.Compare(sortedList[lowerBoundIndex], key) == 0) { return(lowerBoundIndex); } if (isLast && comparer.Compare(key, sortedList[upperBoundIndex]) == 0) { return(upperBoundIndex); } return(middleIndex); } else if (isLast) { lowerBoundIndex = middleIndex; } else if (isFirst) { upperBoundIndex = middleIndex; } else { return(middleIndex); } } if ((method & BinarySearchMethod.FloorClosest) == BinarySearchMethod.FloorClosest) { return(upperBoundIndex); } if ((method & BinarySearchMethod.CeilClosest) == BinarySearchMethod.CeilClosest) { return(lowerBoundIndex); } return(-1); }
public static void InsertInOrdered <T>( this IList <T> sortedList, IEnumerable <T> items, IComparer <T> comparer = null, int fromIndex = 0, int toIndex = -1) { if (sortedList == null) { throw new ArgumentNullException("sortedList"); } if (items == null) { throw new ArgumentNullException("items"); } if (sortedList.IsReadOnly) { throw new ArgumentException(AlterReadOnlyCollectionMsg); } if (comparer == null) { comparer = Comparer <T> .Default; } const BinarySearchMethod method = BinarySearchMethod.CeilClosest | BinarySearchMethod.FirstExact; int index = -1; bool hasPreviousItem = false; T previousItem = default(T); foreach (T item in items) { if (!hasPreviousItem) { index = BinarySearchIndex(sortedList, item, method, fromIndex, toIndex, comparer); } else { int comparison = comparer.Compare(previousItem, item); if (comparison < 0) { index = BinarySearchIndex(sortedList, item, method, index, toIndex, comparer); } else if (comparison > 0) { index = BinarySearchIndex(sortedList, item, method, fromIndex, index, comparer); } } previousItem = item; hasPreviousItem = true; if (index >= sortedList.Count) { sortedList.Add(item); } else if (index < 0) { index = 0; sortedList.Insert(0, item); } else { sortedList.Insert(index, item); } if (toIndex >= 0) { toIndex++; } } }
/// <summary> /// Gets the item with the value after the value. List needs to be in the correct order by the value returned by getValue. /// The method will return the next index in the list above the value (Assuming the list is ordered from low to high). /// </summary> /// <typeparam name="T"></typeparam> /// <param name="list"></param> /// <param name="getValue"></param> /// <param name="startIndex"></param> /// <param name="value"></param> /// <returns></returns> public static int BinarySearchGetItem<T>(this IList list, Func<int, T> getValue, int startIndex, T value, BinarySearchMethod method) where T : IComparable { var lowIndex = startIndex; var highIndex = list.Count - 1; while (highIndex - lowIndex > 5) { var midIndex = (highIndex - lowIndex) / 2 + lowIndex; if (method == BinarySearchMethod.NextHigherValue) { if (getValue(midIndex).CompareTo(value) <= 0) { lowIndex = midIndex + 1; } else { highIndex = midIndex; } } if (method == BinarySearchMethod.PrevLowerValue) { if (getValue(midIndex).CompareTo(value) >= 0) { highIndex = midIndex - 1; } else { lowIndex = midIndex; } } if (method == BinarySearchMethod.PrevLowerValueOrValue) { if (getValue(midIndex).CompareTo(value) > 0) { highIndex = midIndex - 1; } else { lowIndex = midIndex; } } } if (method == BinarySearchMethod.NextHigherValue) { for (var i = lowIndex; i <= highIndex; i++) { if (getValue(i).CompareTo(value) > 0) { return i; } } } else if (method == BinarySearchMethod.PrevLowerValue) { for (var i = highIndex; i >= lowIndex; i--) { if (getValue(i).CompareTo(value) < 0) { return i; } } } else if (method == BinarySearchMethod.PrevLowerValueOrValue) { for (var i = highIndex; i >= lowIndex; i--) { if (getValue(i).CompareTo(value) <= 0) { return i; } } } return -1; }