Inserting Rows Or Cells And Filling Missing Entries In A Series
This page describes a VBA procedure that you can use to insert rows or cells and fill in missing elements of a series of numbers. Suppose you have a partial series of numbers in a range of cells. This code will detect missing entries in the series, insert the appropriate number of rows or cells between the existing entries in the series, and fill those cells with the appropriate values. |
|
|||
|
For example, in the range shown on the far left, the values 2, 3, 6, and 9 are missing from the series of integers in rows 1 through 6. The code shown below will insert the required cells or rows, and then fill in the missing values. After running the code, the result is as shown in the picture on the near left. The values 2, 3, 6, and 9 have been inserted into the series. In this example, the series increment was 1. However, you are not restricted to a series with an increment of 1. The code shown below will properly handle an series increment of any value, including fractional numbers. Unlike the example, the series need not begin in row 1. It may begin in any row. There are two restrictions on the initial data series. First, the existing values must be in ascending order with no interspersed blank cells. Second, the existing values must be round integer multiples of the series increment value. If the existing values do not meet these requirements, the results are undefined. |
|||
The procedure declaration follows:Function InsertAndFillMissingNumbers(RangeToTest As Range, FillStep As Double, _ Optional FullRows As Boolean = False) As Range where FillStep is the increment to use when filling the inserted cells. The existing values in the RangeToTest must be integer multiples of FillStep. FillStep may be a fractional number, such as 1.5. If the existing values are not integer multiples of FillStep, the results are undefined. FullRows indicates whether to insert entire rows or just cells in the column. If FullRows is omitted or False, then only cells within the column of RangeToTest are inserted. If FullRows is True, entire rows are inserted. If all the parameters are correct and the RangeToTest is proper, then the function will return a Range object referring to the expanded range. In the example above, the result of the function is the range D1:D10. If an error occurs, the function returns Nothing. The complete code is shown below: Function InsertAndFillMissingNumbers(RangeToTest As Range, FillStep As Double, _ Optional FullRows As Boolean = False) As Range Dim BottomRow As Long Dim TopRow As Long Dim NumToInsert As Long Dim RowNdx As Long Dim WS As Worksheet Dim ColNum As Long Dim StartRng As Range Dim EndRng As Range Dim Rng As Range '''''''''''''''''''''''''''''' ' Ensure RangeToTest is not ' nothing. '''''''''''''''''''''''''''''' If RangeToTest Is Nothing Then Exit Function End If ''''''''''''''''''''''''''''''''''''' ' Ensure RangeToTest is a single ' column. ''''''''''''''''''''''''''''''''''''' If RangeToTest.Columns.Count > 1 Then Exit Function End If '''''''''''''''''''''''''''''''''''' ' Ensure that there is at least ' one non-blank cell in RangeToTest. '''''''''''''''''''''''''''''''''''' If Application.WorksheetFunction.Count(RangeToTest) = 0 Then Exit Function End If ''''''''''''''''''''''''''''''''''''' ' Ensure that all cell values are ' numeric and not blank. ''''''''''''''''''''''''''''''''''''' For Each Rng In RangeToTest.Cells If Rng.Value = vbNullString Then Exit Function End If If IsNumeric(Rng.Value) = False Then Exit Function End If Next Rng ''''''''''''''''''''''''''''''''''' ' Set some variable values. ''''''''''''''''''''''''''''''''''' With RangeToTest Set WS = .Worksheet Set StartRng = .Cells(1, 1) Set EndRng = .Cells(.Cells.Count) TopRow = .Cells(1, 1).Row BottomRow = .Cells(.Cells.Count).Row ColNum = .Column End With '''''''''''''''''''''''''''''' ' If the bottom cell is empty ' move it up to the last ' non-blank cell. '''''''''''''''''''''''''''''' With WS If .Cells(BottomRow, ColNum).Value = vbNullString Then BottomRow = .Cells(BottomRow, ColNum).End(xlUp).Row End If End With '''''''''''''''''''''''''''''''''''''''''''''' ' Loop RowNdx from the bottom cell upwards, ' with a step of -1. '''''''''''''''''''''''''''''''''''''''''''''' For RowNdx = BottomRow To (TopRow + 1) Step -1 With WS If .Cells(RowNdx, ColNum).Value - FillStep <> .Cells(RowNdx - 1, ColNum).Value Then '''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' The Cell value - FillStep is not equal to the value ' of the cell above it. We need to insert one or more ' rows. Compute the number of rows to insert. Note that ' the division at the end of this line is integer ' division ( the \ operator, not the / operator). '''''''''''''''''''''''''''''''''''''''''''''''''''''''' NumToInsert = (Abs(.Cells(RowNdx, ColNum).Value - .Cells(RowNdx - 1, ColNum).Value) - FillStep) \ FillStep If NumToInsert <> 0 Then If FullRows = True Then '''''''''''''''''''''''''''''''''''''' ' Insert complete rows. '''''''''''''''''''''''''''''''''''''' .Rows(RowNdx).Resize(NumToInsert).Insert Else ''''''''''''''''''''''''''''''''''''''' ' Insert only cells in the RangeToTest ' column. ''''''''''''''''''''''''''''''''''''''' .Cells(RowNdx, ColNum).Resize(NumToInsert).Insert shift:=xlDown End If '''''''''''''''''''''''''''''''''''''''''''''' ' Put the next value in the first inserted ' cell. Then user DataSerise to fill down ' the rest of the new values. '''''''''''''''''''''''''''''''''''''''''''''' .Cells(RowNdx, ColNum).Value = .Cells(RowNdx - 1, ColNum) + FillStep .Cells(RowNdx, ColNum).Resize(NumToInsert, 1).DataSeries rowcol:=xlColumns, Type:=xlLinear, Step:=FillStep End If End If End With Next RowNdx '''''''''''''''''''''''''''''''''''''' ' Return the result range. EndRng ' was set to the bottom of RangeToTest ' and was moved down as a result of the ' inserts, so it is now at the end of ' the expanded range. ''''''''''''''''''''''''''''''''''''''' Set InsertAndFillMissingNumbers = Range(StartRng, EndRng) End Function Finding A Series That Sums To A Specific Value The procedure below is only tangentially related to previous topic on this page, but I couldn't think where else to put it. This procedure will find a contiguous range of cells in column A that sum to the value in cell B1. It will scan down column A until it finds a set of contiguous cells that sum to the value in B1 or until a blank cell is encountered in column A, in which case there is no series that sums to the value in B1. If there is more than one series that sums to B1, only the first such series is found. The range of the series, if found, is highlighted. Sub FindSeries() Dim StartRng As Range Dim EndRng As Range Dim Answer As Long Dim TestTotal As Long Answer = Range("B1") '<<< CHANGE Set StartRng = Range("A1") Set EndRng = StartRng Do Until False TestTotal = Application.Sum(Range(StartRng, EndRng)) If TestTotal = Answer Then Range(StartRng, EndRng).Select Exit Do ElseIf TestTotal > Answer Then Set StartRng = StartRng(2, 1) Set EndRng = StartRng Else Set EndRng = EndRng(2, 1) If EndRng.Value = vbNullString Then MsgBox "No series found" Exit Do End If End If Loop End Sub Testing If A Column Of Numbers Is A Valid Series You can use the formula below to determine if all the entries in a specified range are in the correct series order. That is, whether they are equally spaced, with a specified step increment. In the formula, TheRange is the range of cells to test, and Step is the correct increment between items N and N+1 of the series, going downward in the column of numbers. The formula will return 0 if all the items are separated by the value of Step. For example, if A1:A5 is 2, 4, 6, 8, 10 and Step is 2, the result is 0, indicating that all values are separated by Step. If A1:A5 is 2, 5, 8, 10, 12, the result is 2, indicating that, moving downwards, 2 items (5 and 8 in this example) are not separated by Step. The Step increment should be positive for series in ascending order or negative for series in descending order. This is an array formula, so you must press CTRL+SHIFT+ENTER rather than just ENTER after you type the formula and whenever you edit it later. If you do this properly, Excel will display the formula enclosed in curly braces { } in the formula bar. Click here for more information about working with array formulas. Note that the formula is split in to two lines here for display purposes. When copied to Excel, the formula should be a single line.
=SUM(IF(OFFSET(TheRange,1,0,ROWS(TheRange)-1,1)= If you prefer to use cell references instead of a defined name, use a formula like =SUM(IF(A2:A10=A1:A9+B1,0,1)) where A1:A10 contains the value to be test and B1 contains the Step value. Note that the first range is A2:A10 and second range is A1:A9. Like the previous formula, this formula must be entered with CTRL+SHIFT+ENTER rather than just ENTER.
|