Пример #1
0
        /// <summary>
        /// Calculates the average value of all cells that match the given criterion. The sizes/shapes of
        /// <paramref name="cellsToCompare"/> and <paramref name="potentialCellsToAverage"/> do not have to be the same;
        /// The size and shape of <paramref name="cellsToCompare"/> is applied to <paramref name="potentialCellsToAverage"/>,
        /// using the first cell in <paramref name="potentialCellsToAverage"/> as a reference point.
        /// </summary>
        /// <param name="cellsToCompare">The range of cells to compare against the <paramref name="comparisonCriterion"/>.</param>
        /// <param name="comparisonCriterion">The criterion dictating which cells should be included in the average calculation.</param>
        /// <param name="potentialCellsToAverage">
        ///		If a cell in <paramref name="cellsToCompare"/> passes the criterion, then its
        ///		corresponding cell in this cell range will be included in the average calculation.</param>
        /// <returns>Returns the average for all cells that pass the <paramref name="comparisonCriterion"/>.</returns>
        private CompileResult CalculateAverageUsingAverageRange(ExcelDataProvider.IRangeInfo cellsToCompare, object comparisonCriterion, ExcelDataProvider.IRangeInfo potentialCellsToAverage)
        {
            var sumOfValidValues    = 0d;
            var numberOfValidValues = 0;

            var startingRowForComparison    = cellsToCompare.Address._fromRow;
            var startingColumnForComparison = cellsToCompare.Address._fromCol;
            var endingRowForComparison      = cellsToCompare.Address._toRow;
            var endingColumnForComparison   = cellsToCompare.Address._toCol;

            // This will always look at every cell in the given range of cells to compare. This is done instead of
            // using the iterator provided by the range of cells to compare because the collection of cells that it iterates over
            // does not include empty cells that have not been set since the workbook's creation. This function
            // wants to consider empty cells for comparing with the criterion, but it can be better optimized.
            // A similar problem and optimization opportunity exists in the AverageIfs, SumIf, SumIfs, CountIf, and CountIfs functions.
            for (var currentRow = startingRowForComparison; currentRow <= endingRowForComparison; currentRow++)
            {
                for (var currentColumn = startingColumnForComparison; currentColumn <= endingColumnForComparison; currentColumn++)
                {
                    var currentCellValue = this.GetFirstArgument(cellsToCompare.GetValue(currentRow, currentColumn));
                    if (IfHelper.ObjectMatchesCriterion(currentCellValue, comparisonCriterion))
                    {
                        var relativeRow          = currentRow - startingRowForComparison;
                        var relativeColumn       = currentColumn - startingColumnForComparison;
                        var valueOfCellToAverage = potentialCellsToAverage.GetOffset(relativeRow, relativeColumn);
                        if (valueOfCellToAverage is ExcelErrorValue cellError)
                        {
                            return(new CompileResult(cellError.Type));
                        }
                        else if (ConvertUtil.IsNumeric(valueOfCellToAverage, true))
                        {
                            sumOfValidValues += ConvertUtil.GetValueDouble(valueOfCellToAverage);
                            numberOfValidValues++;
                        }
                    }
                }
            }
            if (numberOfValidValues == 0)
            {
                return(new CompileResult(eErrorType.Div0));
            }
            else
            {
                return(this.CreateResult(sumOfValidValues / numberOfValidValues, DataType.Decimal));
            }
        }
        protected List <int> GetMatchIndexes(ExcelDataProvider.IRangeInfo rangeInfo, string searched)
        {
            var result        = new List <int>();
            var internalIndex = 0;

            for (var row = rangeInfo.Address._fromRow; row <= rangeInfo.Address._toRow; row++)
            {
                for (var col = rangeInfo.Address._fromCol; col <= rangeInfo.Address._toCol; col++)
                {
                    var candidate = rangeInfo.GetValue(row, col);
                    if (searched != null && Evaluate(candidate, searched))
                    {
                        result.Add(internalIndex);
                    }
                    internalIndex++;
                }
            }
            return(result);
        }