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.
|
||||