コード例 #1
0
        /**
         * Finds first (lowest index) exact occurrence of specified value.
         * @param lookupComparer the value to be found in column or row vector
         * @param vector the values to be searched. For VLOOKUP this Is the first column of the
         *  tableArray. For HLOOKUP this Is the first row of the tableArray.
         * @return zero based index into the vector, -1 if value cannot be found
         */
        private static int lookupFirstIndexOfValue(LookupValueComparer lookupComparer, ValueVector vector, MatchMode matchMode)
        {
            // Find first occurrence of lookup value
            int       size          = vector.Size;
            int       bestMatchIdx  = -1;
            ValueEval bestMatchEval = null;

            for (int i = 0; i < size; i++)
            {
                ValueEval     valueEval = vector.GetItem(i);
                CompareResult result    = lookupComparer.CompareTo(valueEval);
                if (result.IsEqual)
                {
                    return(i);
                }
                switch (matchMode)
                {
                case MatchMode.ExactMatchFallbackToLargerValue:
                    if (result.IsLessThan)
                    {
                        if (bestMatchEval == null)
                        {
                            bestMatchIdx  = i;
                            bestMatchEval = valueEval;
                        }
                        else
                        {
                            LookupValueComparer matchComparer = CreateTolerantLookupComparer(valueEval, true, true);
                            if (matchComparer.CompareTo(bestMatchEval).IsLessThan)
                            {
                                bestMatchIdx  = i;
                                bestMatchEval = valueEval;
                            }
                        }
                    }
                    break;

                case MatchMode.ExactMatchFallbackToSmallerValue:
                    if (result.IsGreaterThan)
                    {
                        if (bestMatchEval == null)
                        {
                            bestMatchIdx  = i;
                            bestMatchEval = valueEval;
                        }
                        else
                        {
                            LookupValueComparer matchComparer = CreateTolerantLookupComparer(valueEval, true, true);
                            if (matchComparer.CompareTo(bestMatchEval).IsGreaterThan)
                            {
                                bestMatchIdx  = i;
                                bestMatchEval = valueEval;
                            }
                        }
                    }
                    break;
                }
            }
            return(bestMatchIdx);
        }
コード例 #2
0
        /**
         * Excel has funny behaviour when the some elements in the search vector are the wrong type.
         *
         */
        private static int PerformBinarySearch(ValueVector vector, LookupValueComparer lookupComparer)
        {
            // both low and high indexes point to values assumed too low and too high.
            BinarySearchIndexes bsi = new BinarySearchIndexes(vector.Size);

            while (true)
            {
                int midIx = bsi.GetMidIx();

                if (midIx < 0)
                {
                    return(bsi.GetLowIx());
                }
                CompareResult cr = lookupComparer.CompareTo(vector.GetItem(midIx));
                if (cr.IsTypeMismatch)
                {
                    int newMidIx = HandleMidValueTypeMismatch(lookupComparer, vector, bsi, midIx);
                    if (newMidIx < 0)
                    {
                        continue;
                    }
                    midIx = newMidIx;
                    cr    = lookupComparer.CompareTo(vector.GetItem(midIx));
                }
                if (cr.IsEqual)
                {
                    return(FindLastIndexInRunOfEqualValues(lookupComparer, vector, midIx, bsi.GetHighIx()));
                }
                bsi.narrowSearch(midIx, cr.IsLessThan);
            }
        }
コード例 #3
0
        /**
         * @return zero based index
         */
        private static int FindIndexOfValue(ValueEval lookupValue, ValueVector lookupRange,
                                            bool matchExact, bool FindLargestLessThanOrEqual)
        {
            LookupValueComparer lookupComparer = CreateLookupComparer(lookupValue, matchExact);

            int size = lookupRange.Size;

            if (matchExact)
            {
                for (int i = 0; i < size; i++)
                {
                    if (lookupComparer.CompareTo(lookupRange.GetItem(i)).IsEqual)
                    {
                        return(i);
                    }
                }
                throw new EvaluationException(ErrorEval.NA);
            }

            if (FindLargestLessThanOrEqual)
            {
                // Note - backward iteration
                for (int i = size - 1; i >= 0; i--)
                {
                    CompareResult cmp = lookupComparer.CompareTo(lookupRange.GetItem(i));
                    if (cmp.IsTypeMismatch)
                    {
                        continue;
                    }
                    if (!cmp.IsLessThan)
                    {
                        return(i);
                    }
                }
                throw new EvaluationException(ErrorEval.NA);
            }

            // else - Find smallest greater than or equal to
            // TODO - Is binary search used for (match_type==+1) ?
            for (int i = 0; i < size; i++)
            {
                CompareResult cmp = lookupComparer.CompareTo(lookupRange.GetItem(i));
                if (cmp.IsEqual)
                {
                    return(i);
                }
                if (cmp.IsGreaterThan)
                {
                    if (i < 1)
                    {
                        throw new EvaluationException(ErrorEval.NA);
                    }
                    return(i - 1);
                }
            }

            return(size - 1);
        }
コード例 #4
0
 /**
  * Once the binary search has found a single match, (V/H)LOOKUP steps one by one over subsequent
  * values to choose the last matching item.
  */
 private static int FindLastIndexInRunOfEqualValues(LookupValueComparer lookupComparer, ValueVector vector,
                                                    int firstFoundIndex, int maxIx)
 {
     for (int i = firstFoundIndex + 1; i < maxIx; i++)
     {
         if (!lookupComparer.CompareTo(vector.GetItem(i)).IsEqual)
         {
             return(i - 1);
         }
     }
     return(maxIx - 1);
 }
コード例 #5
0
        /**
         * Finds first (lowest index) exact occurrence of specified value.
         * @param lookupValue the value to be found in column or row vector
         * @param vector the values to be searched. For VLOOKUP this Is the first column of the
         *  tableArray. For HLOOKUP this Is the first row of the tableArray.
         * @return zero based index into the vector, -1 if value cannot be found
         */
        private static int LookupIndexOfExactValue(LookupValueComparer lookupComparer, ValueVector vector)
        {
            // Find first occurrence of lookup value
            int size = vector.Size;

            for (int i = 0; i < size; i++)
            {
                if (lookupComparer.CompareTo(vector.GetItem(i)).IsEqual)
                {
                    return(i);
                }
            }
            return(-1);
        }
コード例 #6
0
        public static int LookupIndexOfValue(ValueEval lookupValue, ValueVector vector, bool IsRangeLookup)
        {
            LookupValueComparer lookupComparer = CreateLookupComparer(lookupValue);
            int result;

            if (IsRangeLookup)
            {
                result = PerformBinarySearch(vector, lookupComparer);
            }
            else
            {
                result = LookupIndexOfExactValue(lookupComparer, vector);
            }
            if (result < 0)
            {
                throw new EvaluationException(ErrorEval.NA);
            }
            return(result);
        }
コード例 #7
0
        public static int XlookupIndexOfValue(ValueEval lookupValue, ValueVector vector, MatchMode matchMode, SearchMode searchMode)
        {
            LookupValueComparer lookupComparer = CreateTolerantLookupComparer(lookupValue, true, true);
            int result;

            if (searchMode == SearchMode.IterateBackward || searchMode == SearchMode.BinarySearchBackward)
            {
                result = lookupLastIndexOfValue(lookupComparer, vector, matchMode);
            }
            else
            {
                result = lookupFirstIndexOfValue(lookupComparer, vector, matchMode);
            }
            if (result < 0)
            {
                throw new EvaluationException(ErrorEval.NA);
            }
            return(result);
        }
コード例 #8
0
        public static int lookupFirstIndexOfValue(ValueEval lookupValue, ValueVector vector, bool isRangeLookup)
        {
            LookupValueComparer lookupComparer = CreateLookupComparer(lookupValue, isRangeLookup, false);
            int result;

            if (isRangeLookup)
            {
                result = PerformBinarySearch(vector, lookupComparer);
            }
            else
            {
                result = lookupFirstIndexOfValue(lookupComparer, vector, MatchMode.ExactMatch);
            }
            if (result < 0)
            {
                throw new EvaluationException(ErrorEval.NA);
            }
            return(result);
        }
コード例 #9
0
        /**
         * Excel seems to handle mismatched types initially by just stepping 'mid' ix forward to the
         * first compatible value.
         * @param midIx 'mid' index (value which has the wrong type)
         * @return usually -1, signifying that the BinarySearchIndex has been narrowed to the new mid
         * index.  Zero or greater signifies that an exact match for the lookup value was found
         */
        private static int HandleMidValueTypeMismatch(LookupValueComparer lookupComparer, ValueVector vector,
                                                      BinarySearchIndexes bsi, int midIx)
        {
            int newMid = midIx;
            int highIx = bsi.GetHighIx();

            while (true)
            {
                newMid++;
                if (newMid == highIx)
                {
                    // every element from midIx to highIx was the wrong type
                    // move highIx down to the low end of the mid values
                    bsi.narrowSearch(midIx, true);
                    return(-1);
                }
                CompareResult cr = lookupComparer.CompareTo(vector.GetItem(newMid));
                if (cr.IsLessThan && newMid == highIx - 1)
                {
                    // move highIx down to the low end of the mid values
                    bsi.narrowSearch(midIx, true);
                    return(-1);
                    // but only when "newMid == highIx-1"? slightly weird.
                    // It would seem more efficient to always do this.
                }
                if (cr.IsTypeMismatch)
                {
                    // keep stepping over values Until the right type Is found
                    continue;
                }
                if (cr.IsEqual)
                {
                    return(newMid);
                }
                // Note - if moving highIx down (due to lookup<vector[newMid]),
                // this execution path only moves highIx it down as far as newMid, not midIx,
                // which would be more efficient.
                bsi.narrowSearch(newMid, cr.IsLessThan);
                return(-1);
            }
        }
コード例 #10
0
ファイル: LookupUtils.cs プロジェクト: missxiaohuang/Weekly
 /**
  * Once the binary search has found a single match, (V/H)LOOKUP steps one by one over subsequent
  * values to choose the last matching item.
  */
 private static int FindLastIndexInRunOfEqualValues(LookupValueComparer lookupComparer, ValueVector vector,
             int firstFoundIndex, int maxIx)
 {
     for (int i = firstFoundIndex + 1; i < maxIx; i++)
     {
         if (!lookupComparer.CompareTo(vector.GetItem(i)).IsEqual)
         {
             return i - 1;
         }
     }
     return maxIx - 1;
 }
コード例 #11
0
ファイル: LookupUtils.cs プロジェクト: missxiaohuang/Weekly
        /**
         * Excel seems to handle mismatched types initially by just stepping 'mid' ix forward to the 
         * first compatible value.
         * @param midIx 'mid' index (value which has the wrong type)
         * @return usually -1, signifying that the BinarySearchIndex has been narrowed to the new mid 
         * index.  Zero or greater signifies that an exact match for the lookup value was found
         */
        private static int HandleMidValueTypeMismatch(LookupValueComparer lookupComparer, ValueVector vector,
                BinarySearchIndexes bsi, int midIx)
        {
            int newMid = midIx;
            int highIx = bsi.GetHighIx();

            while (true)
            {
                newMid++;
                if (newMid == highIx)
                {
                    // every element from midIx to highIx was the wrong type
                    // move highIx down to the low end of the mid values
                    bsi.narrowSearch(midIx, true);
                    return -1;
                }
                CompareResult cr = lookupComparer.CompareTo(vector.GetItem(newMid));
                if (cr.IsLessThan && newMid == highIx - 1)
                {
                    // move highIx down to the low end of the mid values
                    bsi.narrowSearch(midIx, true);
                    return -1;
                    // but only when "newMid == highIx-1"? slightly weird.
                    // It would seem more efficient to always do this.
                }
                if (cr.IsTypeMismatch)
                {
                    // keep stepping over values Until the right type Is found
                    continue;
                }
                if (cr.IsEqual)
                {
                    return newMid;
                }
                // Note - if moving highIx down (due to lookup<vector[newMid]),
                // this execution path only moves highIx it down as far as newMid, not midIx,
                // which would be more efficient.
                bsi.narrowSearch(newMid, cr.IsLessThan);
                return -1;
            }
        }
コード例 #12
0
ファイル: LookupUtils.cs プロジェクト: missxiaohuang/Weekly
        /**
         * Excel has funny behaviour when the some elements in the search vector are the wrong type.
         * 
         */
        private static int PerformBinarySearch(ValueVector vector, LookupValueComparer lookupComparer)
        {
            // both low and high indexes point to values assumed too low and too high.
            BinarySearchIndexes bsi = new BinarySearchIndexes(vector.Size);

            while (true)
            {
                int midIx = bsi.GetMidIx();

                if (midIx < 0)
                {
                    return bsi.GetLowIx();
                }
                CompareResult cr = lookupComparer.CompareTo(vector.GetItem(midIx));
                if (cr.IsTypeMismatch)
                {
                    int newMidIx = HandleMidValueTypeMismatch(lookupComparer, vector, bsi, midIx);
                    if (newMidIx < 0)
                    {
                        continue;
                    }
                    midIx = newMidIx;
                    cr = lookupComparer.CompareTo(vector.GetItem(midIx));
                }
                if (cr.IsEqual)
                {
                    return FindLastIndexInRunOfEqualValues(lookupComparer, vector, midIx, bsi.GetHighIx());
                }
                bsi.narrowSearch(midIx, cr.IsLessThan);
            }
        }
コード例 #13
0
ファイル: LookupUtils.cs プロジェクト: missxiaohuang/Weekly
        /**
         * Finds first (lowest index) exact occurrence of specified value.
         * @param lookupValue the value to be found in column or row vector
         * @param vector the values to be searched. For VLOOKUP this Is the first column of the 
         * 	tableArray. For HLOOKUP this Is the first row of the tableArray. 
         * @return zero based index into the vector, -1 if value cannot be found
         */
        private static int LookupIndexOfExactValue(LookupValueComparer lookupComparer, ValueVector vector)
        {

            // Find first occurrence of lookup value
            int size = vector.Size;
            for (int i = 0; i < size; i++)
            {
                if (lookupComparer.CompareTo(vector.GetItem(i)).IsEqual)
                {
                    return i;
                }
            }
            return -1;
        }
コード例 #14
0
        /**
         * @return zero based index
         */
        private static int FindIndexOfValue(ValueEval lookupValue, ValueVector lookupRange,
                                            bool matchExact, bool FindLargestLessThanOrEqual)
        {
            LookupValueComparer lookupComparer = CreateLookupComparer(lookupValue, matchExact);

            int size = lookupRange.Size;

            if (matchExact)
            {
                for (int i = 0; i < size; i++)
                {
                    if (lookupComparer.CompareTo(lookupRange.GetItem(i)).IsEqual)
                    {
                        return(i);
                    }
                }
                throw new EvaluationException(ErrorEval.NA);
            }

            if (FindLargestLessThanOrEqual)
            {
                //in case the lookupRange area is not sorted, still try to get the right index
                if (lookupValue is NumericValueEval nve)
                {
                    Dictionary <int, double> dicDeltas = new Dictionary <int, double>();
                    for (int i = 0; i < size; i++)
                    {
                        var item = lookupRange.GetItem(i) as NumericValueEval;
                        if (lookupComparer.CompareTo(item).IsEqual)
                        {
                            return(i);
                        }
                        else
                        {
                            dicDeltas.Add(i, item.NumberValue - nve.NumberValue);
                        }
                    }

                    return(dicDeltas.Where(kv => kv.Value < 0).OrderByDescending(kv => kv.Value).First().Key);
                }
                // Note - backward iteration
                for (int i = size - 1; i >= 0; i--)
                {
                    CompareResult cmp = lookupComparer.CompareTo(lookupRange.GetItem(i));
                    if (cmp.IsTypeMismatch)
                    {
                        continue;
                    }
                    if (!cmp.IsLessThan)
                    {
                        return(i);
                    }
                }
                throw new EvaluationException(ErrorEval.NA);
            }

            // else - Find smallest greater than or equal to
            // TODO - Is binary search used for (match_type==+1) ?
            for (int i = 0; i < size; i++)
            {
                CompareResult cmp = lookupComparer.CompareTo(lookupRange.GetItem(i));
                if (cmp.IsEqual)
                {
                    return(i);
                }
                if (cmp.IsGreaterThan)
                {
                    if (i < 1)
                    {
                        throw new EvaluationException(ErrorEval.NA);
                    }
                    return(i - 1);
                }
            }

            return(size - 1);
        }