LinkBack Thread Tools Search this Thread Display Modes
Prev Previous Post   Next Post Next
  #1   Report Post  
Posted to microsoft.public.excel.programming
JAC JAC is offline
external usenet poster
 
Posts: 31
Default Finding the minimum value in a list but excluding zeros - a variationon an old problem

I have a problem in Excel that I should like to solve. It concerns
finding the minimum of a list of numerical values, excluding zeros.

The stock answer, suggested by Chip Pearson and other experts, is to
create an array formula of the type:

{=MIN(IF(B1:B200,B1:B20,FALSE))}, using CTRL + Shift + Return

However, my application requires very many such formulae, so I set
about writing a VBA subroutine to generate the formulae, using code
similar to the fragment below:

With shtHistory
strFormula = "=MIN(IF('" & .Name & "'!R2C" & intCol & ":R" & j & _
"C" & intCol & "<0,"
strFormula = strFormula & "'" & .Name & "'!R2C" & intCol & ":R" &
_
j & "C" & intCol & ",FALSE))"

Set rngCell = ws.Range(ws.Cells(j, cint_COL_C),
ws.Cells(j,cint_COL_C))
rngCell.FormulaArray = strFormula
End With

where j is the row number (long), intCol is the column number where
the relevant data is listed, rngCell is a Range and shtHistory is the
codename of a worksheet and ws is a worksheet.

Also, I calculate other descriptive statistics like Mean, Maximum,
Median, Variance and Standard Deviation, without resorting to
filtering, since zeros are not significant. All works well, but the
workbook takes a long time to load since Excel must calculate
thousands of formulae.

Because most of the data in the worksheets of interest is historic and
not subject to change, it is easy enough to avoid formulae where there
is no filtering, since in VBA we have access to functions like MAX,
MEDIAN, AVERAGE, VAR and STDEV via Application.WorksheetFunction.

The code fragment below shows how I have managed this:

strRange = "R2C" & intCol & ":R" & j & "C" & intCol
strRange = Application.ConvertFormula(strRange, xlR1C1, xlA1)
strRange = "'" & shtHistory.Name & "'!" & strRange
Set rngRange = Range(strRange)

.Cells(j, cint_COL_D) = objFunc.Max(rngRange) '
Maximum
dblTemp = objFunc.Average(rngRange)
.Cells(j, cint_COL_E) = objFunc.RoundDown(dblTemp, 0) ' Mean
.Cells(j, cint_COL_F) = objFunc.Median(rngRange) ' Median

However, the coding of the filtering for Minimum represents something
of a problem, for which I have managed a solution that I regard to be
unsatisfactory.

I wonder if I could elicit the help of the group in providing a better
solution.

To facilitate matters and help understanding, I have constructed a
simple Excel workbook. On Sheet1 I have placed the following 20 values
in cells B1 to B20.

99, 54, 58, 58, 0, 50, 59, 8, 44, 63, 34, 71, 76, 76, 45, 16, 79, 87,
14, 46

Significantly, the list contains a zero in cell B5, but the non-zero
minimum is 8 (in cell B8). The following array formula placed in cell
B22 displays the correct value.

{=MIN(IF(B1:B200,B1:B20,FALSE))}, using CTRL + Shift + Return.

I was hoping to use Filtering to provide a solution in VBA, but it did
not work as I expected, as you can see from the code below.

Option Explicit
Option Base 1

Public Sub TestFiltering()
Dim objFunc As WorksheetFunction
Dim lngCount As Long
Dim rngRow As Range
Dim rngRange As Range
Dim varCriteria As Variant
Dim varCol As Variant

Set objFunc = Application.WorksheetFunction

varCriteria = "0"

' Range spans a single column for a simple list

Set rngRange = Worksheets("Sheet1").Range("B1:B20")

rngRange.AutoFilter ' Ensure filtering is off at the
start

MsgBox "Minimum value: " & objFunc.Min(rngRange), vbInformation,
"Filter not yet on"

rngRange.AutoFilter field:=1, Criteria1:=varCriteria

MsgBox "Minimum value: " & objFunc.Min(rngRange), vbInformation,
"Filter switched on - minimum zero?"

' Now try building a new column vector using the criteria

lngCount = 0

' Determine the number of rows so that we can dimension the
array initially

For Each rngRow In rngRange
If Not rngRow.EntireRow.Hidden Then
lngCount = lngCount + 1
End If
Next rngRow

ReDim varCol(lngCount)

lngCount = 0

For Each rngRow In rngRange
If Not rngRow.EntireRow.Hidden Then
lngCount = lngCount + 1
varCol(lngCount) = rngRow.Value
End If
Next rngRow

MsgBox "Minimum value: " & objFunc.Min(varCol), vbInformation,
"Filter switched on - minimum zero?"

rngRange.AutoFilter ' Finally, ensure filtering is off

Set objFunc = Nothing
Set rngRange = Nothing
Set rngRow = Nothing
End Sub

Does anyone know of a better solution without resorting to building up
an intermediate array? It is possible that I have misunderstood or
missed something that is fundamental.

Many thanks.

JAC
 
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules

Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On


Similar Threads
Thread Thread Starter Forum Replies Last Post
Help! Minimum Excluding zeros across multiple sheets [email protected] Excel Worksheet Functions 5 November 12th 08 06:41 PM
finding minimum value excluding zero bookman3 Excel Discussion (Misc queries) 6 January 31st 07 03:31 AM
Finding Minimum Value in series, excluding zero values [email protected] Excel Worksheet Functions 5 January 30th 07 08:21 PM
Most frequent item in a list (excluding zeros) Andre Croteau Excel Discussion (Misc queries) 3 November 12th 05 06:58 PM
PROBLEM FINDING MINIMUM SUNIL PATEL Excel Programming 2 July 8th 04 01:47 PM


All times are GMT +1. The time now is 06:46 AM.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Copyright ©2004-2025 ExcelBanter.
The comments are property of their posters.
 

About Us

"It's about Microsoft Excel"