Example #1
0
        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);
        }
Example #2
0
        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;
        }