View Full Version : VBA to replace ranges of array formulae
brettdj
11-25-2005, 08:01 PM
In http://vbaexpress.com/forum/showthread.php?t=6006 I had a good whinge about the worst model I'd had the misfortune to come accross, the range entered array monster
 
I've now had an interesting follow up question. Is it possible to write VBA to replace all the array formula in the workbook ... all 165 sheets blah blah blah
 
First thoughts are that it may be possible, ie using RegEx to parse all the array refs and then enter in discrete cell address, along the lines of my cell reference example in http://vbaexpress.com/kb/getarticle.php?kb_id=68 but it would be difficult
 
Has anyone tried or seen this done before?
 
Cheers
 
Dave
johnske
11-25-2005, 08:12 PM
In http://vbaexpress.com/forum/showthread.php?t=6006 I had a good whinge about the worst model I'd had the misfortune to come accross, the range entered array monster
 
I've now had an interesting follow up question. Is it possible to write VBA to replace all the array formula in the workbook ... all 165 sheets blah blah blahProbably - example workbook?
 
First thoughts are that it may be possible, ie using RegEx to parse all the array refs and then enter in discrete cell address, along the lines of my cell reference example in http://vbaexpress.com/kb/getarticle.php?kb_id=68 but it would be difficult
 
Has anyone tried or seen this done before?
 
Cheers
 
Dave Not me...
brettdj
11-25-2005, 10:24 PM
For example, in cells D6:F6 there is a range entered array formula
{=D1:F1+D2:F2*D4:F4}
 
D6 needs to become  =D1+D2*D4
E6 needs to become  =E1+E2*E4
F6 needs to become  =F1+F2*F4
 
Cheers
 
Dave
Ken Puls
11-25-2005, 11:03 PM
Curious... would it be that difficult?  I can see the logic, I think...
The one thing that we can guarantee in this case is that the formulas are all relative, correct? So if we were to break down the formula you gave into it's components:
D1:F1
+
D2:F2
*
D4:F4
If, in the first component, the column letters are different on either side of the :, then results need to be run over columns.  If the row numbers are different in the first component, then over rows.  We'd need to work out how many columns/rows to deal with.
We should then be able to extract that the first formula is D1+D2*D4.  Copy the formula we broke out into the remaining ranges to be done, based on the column/row count above.
The hardest part would be breaking it into it's components to begin with. But somehow the RegEx master could be up to it, I'm thinking.  :)
Am I off base here?
johnske
11-26-2005, 12:11 AM
Well, here's what I got so far for returning the cell formulas (in msgboxes here) and whether thay're an array or not Ken - go for it :) Option Explicit
 
Sub CellFormulaIs()
Dim Cell As Range
For Each Cell In Cells.SpecialCells(xlCellTypeFormulas)
With Cell
'not an array formula
If .HasArray = False Then
MsgBox .Address & _
" Formula is: " & .Formula
Else
'multiple result array
If IsArray(.CurrentArray) Then
MsgBox .CurrentArray.Address & _
" Formula is: " & .Formula & " (multiple array)"
'single result array
ElseIf .CurrentArray <> .Formula Then
MsgBox .CurrentArray.Address & _
" Formula is: " & .Formula & " (single array)"
End If
End If
End With
Next
End Sub
brettdj
11-26-2005, 12:55 AM
Thanks guy - yep, thats what I was thinking
 
Find an array in column F (I left out that they should always start there - sorry) by using FIND and xlCellTypeFormulas and do a end(xltoright) to check the end array position. Then parse out the first reference in column F, and then copy the relative formula accross
 
The parsing may be the messy bit.
 
I googled this question and was somewhat surprised not to find anything
 
Cheers
 
Dave
Ken Puls
11-27-2005, 12:36 AM
Okay, how's this?
I didn't put in a lot of effort for trying to meet best practices here, so just keep that in mind with the critiques.  ;)
I modified the multicell array part of John's routine, added a function to check if a character was an alpha character (probably a better way to do this), and then made a function to basically stip out the second half of any range.  (ie A1:A30 becomes A1)
It does seem to work for both columns and rows.  I'm sure it's easily broken though, but I'll put it out there for someone else to kick around.  :)
Sub NukeArrays()
    Dim sFirstCell As String, sLastCell As String
    Dim sFormula As String
    Dim Cell As Range
    For Each Cell In Cells.SpecialCells(xlCellTypeFormulas)
        With Cell
             'not an array formula
            If .HasArray = False Then
                MsgBox .Address & _
                " Formula is: " & .Formula & " (No Array)"
            Else
                 'multiple result array
                If IsArray(.CurrentArray) Then
                    sFirstCell = Left(.CurrentArray.Address, InStr(1, .CurrentArray.Address, ":") - 1)
                    sLastCell = Right(.CurrentArray.Address, InStr(1, .CurrentArray.Address, ":") - 1)
                    sFormula = CarveUpArray(.Formula)
                    Range(.CurrentArray.Address).ClearContents
                    Range(sFirstCell).Formula = sFormula
                    Range(sFirstCell).Copy
                    Range(sFirstCell & ":" & sLastCell).PasteSpecial Paste:=xlPasteFormulas
                    
                     'single result array
                ElseIf .CurrentArray <> .Formula Then
                    MsgBox .CurrentArray.Address & _
                    " Formula is: " & .Formula & " (single array)"
                End If
            End If
        End With
    Next
End Sub
Function IsAlpha(sLetter As String) As Boolean
Dim AlphaArray As String
AlphaArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
If InStr(1, AlphaArray, sLetter, vbTextCompare) > 0 Then IsAlpha = True
End Function
Function CarveUpArray(sFormula As String) As String
Dim lChars As Long
Dim bskip As Boolean
For lChars = 1 To Len(sFormula)
    If bskip = True Then
        If Not IsAlpha(Mid(sFormula, lChars + 1, 1)) Then
            If Not IsNumeric(Mid(sFormula, lChars + 1, 1)) Then bskip = False
        End If
    Else
        If Mid(sFormula, lChars, 1) = ":" Then
            bskip = True
        Else
            CarveUpArray = CarveUpArray & Mid(sFormula, lChars, 1)
        End If
    End If
Next lChars
End Function
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.