Test test
Some notes for this main Thread post
https://www.eileenslounge.com/viewto...310171#p310171
Test test
Some notes for this main Thread post
https://www.eileenslounge.com/viewto...310171#p310171
Last edited by DocAElstein; 10-15-2023 at 01:56 PM.
Hi Jeff,
Why have you deleted this Thread_...
http://imgur.com/m17fPbU ( http://www.excelforum.com/hello-intr...-thoughts.html )
_.. which you started?, as well as my Reply:
Hi Jeff,
I do not quite understand what you are asking?
( The OP said he was unable to change the Title. http://www.excelforum.com/excel-gene...ml#post4591186 )
Are you suggesting that Special-K should be given an infractions for continuing after your Moderator's message?
If so I think the issue that needed to be addressed first is with the OP and why he is / was unable to change the Title. Just my Opinion.. I think you should have followed that up. http://www.excelforum.com/excel-gene...ml#post4591186 Just my Opinion.. ***
But I do agree that a good title is very important. That is one rule that I do feel is very important.
_.....
***
_ Possibly the OP was posting at a time when there were software problems making editing difficult ( he mentions the dreaded spinning wheel that we all hate so much ).
Or
_ He is using one of the Forum styles other than default. Sometimes not all options are available in all styles:......
ForumStyles.JPG http://imgur.com/hKhyE8M
http://www.excelforum.com/the-water-...ml#post4543964
http://www.excelforum.com/the-water-...ml#post4543988
http://www.excelforum.com/the-water-...ml#post4544280
_Also as a new OP -he may not yet be able to Edit posts!
duckersjNewOpIsMatey.JPG http://imgur.com/tTubchA
( I beleive such things may be restricted for new users to help prevent spammers joining and making a mess )
Alan
P.s. Do you realise that you are posting this http://www.excelforum.com/hello-intr...-thoughts.html in the Sub Forum (Off Topic) Hello..Introduce yourself ?
JeffHelloIntroduceInfractionsWonk.JPG http://imgur.com/m17fPbU
I do not think that is the appropriate Sub Forum. ( Probably Water Cooler or Suggestions for Improvement or Feedback / Comments / Suggestions etc. But just my opinion. I do not think you should receive an infraction for incorrect posting.. Lol... – Possibly just a negative reputation would do .. Lol... --- seeking anyone's thoughts ??
Recursion Procedures in Excel VBA. Recursion technique in coding
Procedures Calling others
I think this can be very easy to understand. I think it has been made unnecessary hard to understand by two things:
_ (i) The usual initial explanation or definition : …. ..” A procedure that calls itself is a recursive procedure…” – forget that it is rubbish
_ (i) if you are familiar with stepping through a code in the VBEditor using F8 debug mode, ( http://www.eileenslounge.com/viewtop...247121#p247121 ) , then you might be confused into believing _ (i) if you step through coding which goes into recursion.
Procedures Calling others
A procedure ( also known as code , coding , or routine, or program ) is just a set of instruction which are followed when it “runs”
A procedure Calling another procedure is quite common in even simple programming. This just means that a running procedure has a code line that instructs another procedure to start. The technical term is that the original procedure Calls another.
What may not be immediately obvious, is that
_ a) generally VBA coding can only do one procedure at a time.
_ b) for a simple Calling of a procedure from another, the procedure doing the Calling will pause , whilst the Called procedure runs. When that Called procedure Ends , then the original paused procedure will carry on from the point where it paused, which will necessarily be the Call point
These points might not be so obvious by looking at the coding in the VB Editor window. For example, below is an initial code passing some information to a second procedure which it Calls
Those actual “procedures” are just instructions. You could consider those as your master copy, or on the other hand you might just consider them as one of many possible copies: There is nothing to stop you storing copies of all that all over the place, on computers, on paper etc… in any case, VBA will have made a note of where these instructions are. When you start the first code running, VBA will make a copy of the instructions ( Sub1 ) and run that. When VBA then reaches the code line Call Sub2(CpyNo:=StrtCpyNo, Msg:="Initial Message") , it will pause Sub1 , while it makes a copy of the second procedure instructions, Sub2 , and it will run through those instructions until they are finished, at which point it resumes Sub1 at the Call code line.
If you go unto the VBEditor ( Via keys Alt+F11 from Excel ) , then click anywhere in Sub1 and hit key F8 , then you will proceed in step mode through the coding. If you bear in mind the points _ a) and _ b) , then you might be able to follow and understand what is going on.
Because the first routine pauses whilst the second routine is done, we could attempt to write the equivalent single routine, which progresses through the same steps, in the same order as when the above coding is run by starting Sub 1Code:Option Explicit Sub Sub1() Dim StrtCpyNo As Long ' To count copy number of code instructions being run Let StrtCpyNo = 1 Call Sub2(CpyNo:=StrtCpyNo, Msg:="Initial Message") MsgBox Prompt:="Ending main procedure" End Sub ' Code above is Main calling procedure_________________________________________________________________________________ ' Code below is called procedure Sub Sub2(ByVal CpyNo As Long, ByVal Msg As String) Dim CopyNo As Long ' This is to indicate which copy of Sub2 is currently running Let CopyNo = CpyNo MsgBox Prompt:="You are Starting Sub2 , copy " & CopyNo MsgBox Prompt:="You are Ending Sub2 , copy " & CopyNo End Sub
Some things to note, before moving onto recursion things.. :Code:Sub Sub1Sub2() Dim StrtCpyNo As Long Let StrtCpyNo = 1 'Call Sub2( CpyNo:=StrtCpyNo, Msg:="Initial Message") ' Sub 2 Dim CpyNo As Long: Let CpyNo = StrtCpyNo: Dim Msg As String: Let Msg = "Initial Message" Dim CopyNo As Long Let CopyNo = CpyNo MsgBox Prompt:="You are Starting Sub2 , copy " & CopyNo MsgBox Prompt:="You are Ending Sub2 , copy " & CopyNo ' End Sub2 MsgBox Prompt:="Ending main procedure" End Sub
_ It is very easy to loose track of where you are when procedures Call others. It is particularly difficult to keep track when you are stepping through coding experiencing recursion processes. The reason for this is the following: As mentioned, the written coding is just copies of instructions. If you are doing any sort of debugging, such as the step F8 mode, then Microsoft has decided to indicate for you where you are in the copies shown in the VB Editor. That is not too bad for the coding shown so far. The problem comes in a recursion process, where, in this case, our Sub2 “Calls itself”.
What would be sensible for Microsoft to do in that case would be to show you a new copy of Sub2 , and step you through that second copy. Unfortunately that does not occur. Instead it shows you going through the same copy of Sub2
Therefore as you go through such a recursion process you will never know in which copy you are running
_ Following on from the last point: I don’t think I have ever experienced using recursion routines where it has not been useful to have an integer variable which keeps track of what copy I am in. I would personally recommend always to have such a variable
In the coding shown so far, this is my variables CopyNo and CpyNo
So far they have always been 1, as I have only been running 1 copy of Sub2
As we proceed, it should be clear how we can arrange that the variable always has a number equal to the copy number of the second routine, Sub2 , which is currently running
I am thinking of an alternative approach, the idea being to reduce on the steps to reorganising the array at every swap stage.. the idea came from 2 things …
_1 The recursion routine is fed currently the row indices of the rows that need to be sorted.
_2 We can use the VBA Application.Index Method allows us to re sort an array “ in one go “ via a code line like , pseudo formula..
arrOut() = App.Indx( ArrIn() , {1;3;2} , {1,2,3} )
arrOut() = App.Indx( ArrIn() , row indices , column indicies )
The above code line would change an arrIn() like this …_
A b c
D e f
G h I
_ … to a given output in arrOut() like this:
A b c
G h I
D e f
So the idea is that we sort the indices values, and then re apply the formula above
At this stage I propose modifying the existing code so as to have a better chance of a direct comparison in performance.. Both will be then subject to similar general inefficiencies arising from the very opened out explicit form of the codings generally
Here the basic modifications for Sub SimpleArraySort7(__ , Sub TestieSimpleArraySort7()
Global Variables
To help simplify the comparison and so reduce the changes to the routines, I will have a couple of Global variables at the top of the module and outside any routine for the row and column indices
Dim Cms() As Variant, Rs() As Variant
This will allow me to refer to, that is to say change and use, in any copy of the recursion routine. (It would also be an alternative place here at the top of the module and outside any routine for our main array, arrTS(): we could then always refer to this, and then not need the ByRef arsRef() at the signature line of the recursion routine. But for now I will leave that as it is for closer comparison of the routines )
To help in the development of this coding and to help with the explanation here, I have also moved the variable for the test range, RngToSort , to the top of the module and outside any routine to make it a global variable: This way I can use it’s dimensions to position intermediate paste outs of the arrTS(). For example , I have added a section immediately after the end of the main outer loop == for sorting, ' Captains Blog, Start Treck , which pastes out the current state of the sorted array , arrTS(), along with the current state of the indices, Rs()
For color=Blue]Sub[/color] SimpleArraySort7(__ I will also include a new array variable , as a global variable, arrIndx(). This I will fill by the formula line ofCode:' Captains Blog, Start Treck Let RngToSort.Offset((RngToSort.Rows.Count * (CopyNo + 1)), 0).Value = arsRef() RngToSort.Offset((RngToSort.Rows.Count * (CopyNo + 1)), -1).Resize(UBound(Rs(), 1), UBound(Rs(), 2)).Value = Rs() Debug.Print " Running Copy " & CopyNo & " of routine." & vbCr & vbLf & " Sorted rows " & strRws & " based on values in column " & Clm & vbCr & vbLf & " Checking now for Dups in that last sorted list" & vbCr & vbLf
arrIndx() = Application.Index(arrIndx(), Rs(), Cms())
Modifying indices values in main sort loop sorting
The way the current coding is organised this is fairly simple. We have sections where row elements are swapped. We use the row information in the variables rOuter and rInner. So quite simply, we do the same swap for row indices,
Initial row indicees
Evaluate(Row(1to15)).JPG : https://imgur.com/UVTQCYO
Evaluate(Column(1to6)).JPG : https://imgur.com/jbaZdgJ
Simple recursion example 2
In simple general terms a recursion routine can be an efficient way to do a sort of looping while looking for something. Sometimes the idea of “tunnelling down” or digging down” can describe the situation well. Sometimes a standard looping routine of the Do Loop While type form can replace a recursion routine more efficiently ( https://www.excelforum.com/tips-and-...omparison.html )
The characteristic that possibly distinguishes recursion routines is the ability to seemingly intelligently go up and down: Compare it to the situation of digging down , whereby from time to time you come back up a bit, then dig down again in a slightly different direction. That is best illustrated by using a recursion routine for one of its most common practical uses, that of searching through Folders and sub Folders in a Directory. That will be done in the over next post.
As a pre requisite to that we will demonstrate how a much simpler recursion routine may dig down until a condition is met, and then, thereafter it comes back up, level for level , i.e. copy for copy. This usage is very similar to the standard looping routine of the Do Loop While type form except that you have a last coming back up the levels, or coming back up the copies, which you would not have with a simple Do Loop While type form ( https://www.excelforum.com/developme...ml#post4221234 )
We did not experience this coming back up in the last code because we Stoped. In general use of a recursion process, we do not have a simple way to end with like If ____ Then End Sub. Such a solution would be difficult to implement in a recursion process, as we would be ending the current copy with the End Sub.
So generally a recursion process ends by somehow “coming back up levels” or ending each copy one after the other, either
in sequence for a simple routine,
or
after going back and forth / up and down in a more complicated implementation of a recursion process.
In most cases the coming back up is rarely experienced. We have specifically a message box at that point to show when a copy of the routine is ended. In practical uses what happens at this point is ether nothing, or for more complex implementation of recursion, we may be in a Loop at that point which would determine if we “go back down” again: Some controlled looping at this point is what triggers the possibility to “go back down” , pseudo…
Sub Sub2( CpyNo , ______ )
CurrentCopyNumber=CpyNo
‘
‘
__Do
___Call Sub2(CurrentCopyNumber+1 , ______ )
__Loop While__
MsgBox Prompt:="You are Ending Sub2 , copy " & CurrentCopyNumber
End Sub
This will be discussed in the over next post.
For now we look at the simple case
One immediate way to stop us going further than say the second copy, would be to change our last coding pair from…_
_... toCode:Sub Sub1() Dim StrtCpyNo As Long ' To count copy number of code instructions being run Let StrtCpyNo = 1 Call Sub2(CpyNo:=StrtCpyNo, Msg:="Initial Message") MsgBox Prompt:="Ending main procedure" End Sub ' Code above is Main calling procedure '____________________________________________________________________ ' Code below is called procedure Sub Sub2(ByVal CpyNo As Long, ByVal Msg As String) Dim CopyNo As Long ' This is to indicate which copy of Sub2 is currently running Let CopyNo = CpyNo MsgBox Prompt:="You are Starting Sub2 , copy " & CopyNo Call Sub2(CpyNo:=CopyNo + 1, Msg:="Message coming from Sub2, copy " & CopyNo & "") MsgBox Prompt:="You are Ending Sub2 , copy " & CopyNo End Sub
You can safely run the above coding, ( by running Sub1 ) , in normal mode, as it will no longer try to go on for ever. But it is probably more demonstrative to use debug F8 modeCode:Sub Sub1() Dim StrtCpyNo As Long ' To count copy number of code instructions being run Let StrtCpyNo = 1 Call Sub2(CpyNo:=StrtCpyNo, Msg:="Initial Message") MsgBox Prompt:="Ending main procedure" End Sub ' Code above is Main calling procedure '_____________________________________________________________________________ ' Code below is called procedure Sub Sub2(ByVal CpyNo As Long, ByVal Msg As String) Dim CopyNo As Long ' This is to indicate which copy of Sub2 is currently running Let CopyNo = CpyNo MsgBox Prompt:="You are Starting Sub2 , copy " & CopyNo If CopyNo < 2 Then Call Sub2(CpyNo:=CopyNo + 1, Msg:="Message coming from Sub2, copy " & CopyNo & "") MsgBox Prompt:="You are Ending Sub2 , copy " & CopyNo End Sub
Here is an attempt to show the last run as Excel VBA actually experienced it, - running Sub1 followed by two separate copies of Sub2, or rather
Start Sub1
_Start Sub2Copy1
___Start Sub2Copy2
___End Sub2Copy2
_End Sub2Copy2
End Sub1
Code:Sub Sub1Sub2Sub2() Dim StrtCpyNo As Long ' To count copy number of code instructions being run Let StrtCpyNo = 1 'Call Sub2(CpyNo:=StrtCpyNo, Msg:="Initial Message") ' Sub2 Copy 1 Dim CpyNo As Long: Let CpyNo = StrtCpyNo: Dim Msg As String: Let Msg = "Initial Message" Dim CopyNo As Long ' This is to indicate which copy of Sub2 is currently running Let CopyNo = CpyNo MsgBox Prompt:="You are Starting Sub2 , copy " & CopyNo If CopyNo < 2 Then 'Call Sub2(CpyNo:=CopyNo+1, Msg:="Message coming from Sub2, copy " & CopyNo & "") ' Sub2 Copy 2 Dim CpyNo_ As Long: Let CpyNo_ = CopyNo + 1: Dim Msg_ As String: Let Msg_ = "Message coming from Sub2, copy " & CopyNo & "" Dim CopyNo_ As Long ' This is to indicate which copy of Sub2 is currently running Let CopyNo_ = CpyNo_ MsgBox Prompt:="You are Starting Sub2 , copy " & CopyNo_ End If If CopyNo_ < 2 Then Else MsgBox Prompt:="You are Ending Sub2 , copy " & CopyNo_ End If 'End Sub2 ' End Copy 2 of Sub2 MsgBox Prompt:="You are Ending Sub2 , copy " & CopyNo 'End Sub2 ' End Copy 1 of Sub2 MsgBox Prompt:="Ending main procedure" End Sub
I sometimes wonder whether we fool ourselves into thinking that these things are non looping. I don’t think any of us is privy to exactly what Excel is doing behind the scenes when these things work. The lack of clear documentation to these “array” type workings and the little fiddles you have to do sometimes to get these to work, makes me wonder if anyone knows exactly what is going wrong. Here is one of not many theories about how these sort of things might work.. http://www.excelfox.com/forum/showth...on-and-VLookUp That might suggest that what happens with these Evaluate Range things is similar to how maybe the CSE Array Entry formulas work in spreadsheets:
It suggests that we maybe “tap in” to something that gets done anyway whether we want to or not, and as such we don’t add too much extra. This something could be a “along the row, down a column, along a row…” type thing like a raster across an old telly screen which updates a complete screen/ worksheet. When we define the area in the initial selection of the spreadsheet area before adding our formula in a type 2 CSE Array Entry we may simply be exposing a large area rather than the usual single cell in a complete screen update. In other words the extra information for a multi cell range is there anyway and all we do is open up a bigger window so that we see it at once.
As far as I know, Evaluate was / is something to let you construct a string using both Excel spreadsheet and VBA stuff and then evaluate that string as if you wrote it manually in a spreadsheet cell.
Whether or not it was planned that it could be used in the way that people like Rick do as a sort of hidden type 2 CSE Array Entry formula , or whether that is an accident, I don’t know.
I don’t think I have ever noticed that these things wont work as a type 2 CSE Array Entry , ( occasionally they don’t work in evaluate and we have to coerce them into working ) , so taking Ricks last masterpiece and putting it in a spreadsheet like this will confirm that it works
_____ Workbook: NormanOrrinFilter.xlsm ( Using Excel 2007 32 bit )Code:Dim LastRow As Long, strEval As String Let LastRow = Cells(Rows.Count, "A").End(xlUp).Row Let strEval = Replace(Replace("IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A2:A#,"" "",""""),"","","""")),IF(LEFT(A1:A@,4)=""2018"",TRIM(A1:A@&"" ""&A2:A#),""""),IF(LEFT(A1:A@,4)=""2018"",A1:A@,""""))", "#", LastRow + 1), "@", LastRow) Range("B1:B" & LastRow).FormulaArray = "=" & strEval Debug.Print strEval 'IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A2:A1," ",""),",","")),IF(LEFT(A1:A0,4)="2018",TRIM(A1:A0&" "&A2:A1),""),IF(LEFT(A1:A0,4)="2018",A1:A0,""))
Worksheet: Rick
Row\Col B 1 2 3 4 5 6 7 8 9 10 112018, 1, 90515, 10024515, G9, SBlabla (HQ), CHE, BLABLA, blabla, 10012098, 12003.5 122018, 1, 90629, 10022334, P3, BLABLA blabla (blablabla), CHE, BLABLA,blabla, 10033609, 13941.72 132018, 1, 90709, 10020009, P4, Blabla og Blalala (NY), CHE, Blabla,Bla-ah, 10006098, 15392.64 14 152018, 1, 90765, 10012123, P4, Ch of Blabla(Blabla of Blabla), CHE, BLA-BLA,Bla Blabla, 10005678, 16231.7 16 172018, 1, 90712, 10022908, P4, Snr BLA Off (Strat BLa, BLA), CHE, BLABLA,Bla BLabla, 10023234 14900.28 18 192018, 1, 90919, 10020984, P2, Ass BLA Balbla, CHE, BLA,Blabla, 10033098, 10486.33 202018, 1, 95706, 10023098, NB, Assc BLA Blabal (LatBLAa), BLA, BLABLABLA,Blabla, 10034318, 7566.31 21 22 23 24 25 26 27 28 292018, 1, 95716, 10018763, NA, Asst BLA Off (Blabla & Multi-BLa), BLA, BLA,Bla, 10097776, 8607.96 302018, 1, 99716, 10026132, G5, Snr BLA Asst (Bla Blabla), BLA, BLABLA,bla BLa, 18767043, 5477.44 312018, 1, 99716, 10016545, G6, Blabla Blabla (BLA), BLA, BLABLABLA,Blabla, 1097029, 5325.3 32 33
_.________________________________--
I would guess that whoever wrote the .SpecialCells did that quite efficiently. Who knows, they may even have used some of this “hidden array “ techniques to do it.
So a combination of .SpecialCells and evaluate range one liners sounds an attractive combination , in my opinion.
_._________
Coming back to the solution from Rick… I was interested to work through it.. so I did. I put my workings here, as the OP or anyone else viewing this thread might be interested.
Alan
Post to support this Thread:
http://www.excelfox.com/forum/showth...0888#post10888
_1) This part of Rick’s solution
Evaluate(Replace(Replace("IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A2:A#,"" "",""""),"","","""")),IF(LEFT(A1:A@,4)=""2018"",TRIM(A1:A@&"" ""&A2:A#),""""),IF(LEFT(A1:A@,4)=""2018"",A1:A@,""""))", "#", LastRow + 1), "@", LastRow))
I have seen something similar to this before, but it is lost to mankind hidden down in the comment section of a Blog site, Allen Wyatt’s I think…… so its nice that something like this has seen the light of day here… To help simplify the explanation, lets take it that we know our range , ( http://www.excelfox.com/forum/showth...-row#post10870 ) so we have LastRow = 40
Two arbitrarily chosen characters, @ and # , are being used to enter into the main formula the LastRow or LastRow +1
Pseudo like we are doing this sort of thing
Replace( “A#” , “#” , “40” ) in order to end up with like “A40”
By inspection of the main formula, and with a bit of eye straining you can probably see where you replace those @ and # with 40 and 41
Just to be sure , running this will get you a nice copy able version of the main formula in the immediate window , ( after running you Hit Ctrl+g from the VB Editor to get the immediate window up):
That did work.JPG : https://imgur.com/01sQ91XCode:Sub ThisShouldWork() Dim LastRow As Long, strEval As String Let LastRow = Cells(Rows.Count, "A").End(xlUp).Row Let strEval = Replace(Replace("IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A2:A#,"" "",""""),"","","""")),IF(LEFT(A1:A@,4)=""2018"",TRIM(A1:A@&"" ""&A2:A#),""""),IF(LEFT(A1:A@,4)=""2018"",A1:A@,""""))", "#", LastRow + 1), "@", LastRow) 'Range("B1:B" & LastRow).FormulaArray = "=" & strEval Debug.Print strEval 'IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A2:A41," ",""),",","")),IF(LEFT(A1:A40,4)="2018",TRIM(A1:A40&" "&A2:A41),""),IF(LEFT(A1:A40,4)="2018",A1:A40,""))
_._______________________-
Before moving on a useful note: It is always useful when developing these formulas to view the string in the Immediate window: That can help with tricky syntaxes : The formula seen on the Immediate window must look like a formula in the same syntax as you would manually type it into a cell. So you can see immediately if you get something wrong , such as an error in the finally seen quotes.
_.__________________________
So we have our final formula:
IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A2:A41," ",""),",","")),IF(LEFT(A1:A40,4)="2018",TRIM(A1:A40&" "&A2:A41),""),IF(LEFT(A1:A40,4)="2018",A1:A40,""))
The way these formulas appear to work within the Evaluate(“ “) appears to be tapping into an along the columns , down a row, then along the columns… type updating raster to update a worksheet. The available output then seems to be that which encompasses the deepest and widest ranges. It is a ,little bit more complicated than that ( http://www.excelfox.com/forum/showth...on-and-VLookUp ) , but for our formula we have nice regular equally sized ranges so we are expecting an output of 1 “wide” and 40 “deep”. So for analysis purposes, we can reduce the formula to 40 similar ones.
Lets take the example of the formula for the 13th “down” output ..
IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")),IF(LEFT(A13,4)="2018",TRIM(A13&" "&A14),""),IF(LEFT(A13,4)="2018",A13,""))
Clearly we need to look at this data to see what that formula will do, because this data is used in that formula
_____ Workbook: NormanOrrinRickFilter.xlsm ( Using Excel 2007 32 bit )
Worksheet: Rick
Row\Col A 132018, 1, 90709, 10020009, P4, Blabla og Blalala (NY), CHE, Blabla,Bla-ah, 1410006098, 15392.64
We have some nested IFs , and I find it is always a good idea to break those down so that we can start doing them as Excel or VBA would do them, that is to say from the middle working outwards. I tend to do this in a text editor with a horizontal scroll bar, or in the VB Editor window
Formula in VB Editor as comment.JPG : https://imgur.com/3cjyqSR
So this is what we have, broken down into the constituent IF sections.
( It may be better to copy this and view in your VB Editor in a wide window. I am working from the bottom , upwards )
Examining the first line , I can evaluate the two innermost IFs and reduce the formula toCode:' IF( ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")), IF(LEFT(A13,4)="2018" , TRIM(A13" "&A14) , "") , IF( LEFT(A13,4)="2018" , A13 ,"" ) ) ' IF( ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")),IF(LEFT(A13,4)="2018",TRIM(A13" "&A14),"") , IF(LEFT(A13,4)="2018",A13,"") ) ' IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")),IF(LEFT(A13,4)="2018",TRIM(A13" "&A14),""),IF(LEFT(A13,4)="2018",A13,""))
I will now evaluate some of those SUBSTITUTEsCode:' IF( ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")), TRIM(A13" "&A14) , A13 ) ' IF( ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")), IF(LEFT(A13,4)="2018" , TRIM(A13" "&A14) , "") , IF( LEFT(A13,4)="2018" , A13 ,"" ) )
( Excel Substitute, seems to work similarly to VBA Replace )
( I am guessing that 0+ will ensure that a number will not be mistaken as a text )Code:' IF( ISNUMBER(0+1000609815392.64), TRIM(A13" "&A14) , A13 ) ' IF( ISNUMBER(0+SUBSTITUTE(10006098,15392.64),",","")), TRIM(A13" "&A14) , A13 )
For the case of the 13th “down” formula the final steps in the evaluation go as follows
Here are all the steps together againCode:' 2018, 1, 90709, 10020009, P4, Blabla og Blalala (NY), CHE, Blabla,Bla-ah, 10006098, 15392.64 ' TRIM(A13" "&A14) ' IF( True , TRIM(A13" "&A14) , A13 )
The final result will appear in the 13th down position of the 40 “deep” array final results for the entire formula evaluation.Code:' 2018, 1, 90709, 10020009, P4, Blabla og Blalala (NY), CHE, Blabla,Bla-ah, 10006098, 15392.64 ' TRIM(A13" "&A14) ' IF( True , TRIM(A13" "&A14) , A13 ) ' IF( ISNUMBER(0+1000609815392.64), TRIM(A13" "&A14) , A13 ) ' IF( ISNUMBER(0+SUBSTITUTE(10006098,15392.64),",","")), TRIM(A13" "&A14) , A13 ) ' IF( ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")), TRIM(A13" "&A14) , A13 ) ' IF( ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")), IF(LEFT(A13,4)="2018" , TRIM(A13" "&A14) , "") , IF( LEFT(A13,4)="2018" , A13 ,"" ) ) ' IF( ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")), IF(LEFT(A13,4)="2018" , TRIM(A13" "&A14) , "") , IF( LEFT(A13,4)="2018" , A13 ,"" ) ) ' IF( ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")),IF(LEFT(A13,4)="2018",TRIM(A13" "&A14),"") , IF(LEFT(A13,4)="2018",A13,"") ) ' IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")),IF(LEFT(A13,4)="2018",TRIM(A13" "&A14),""),IF(LEFT(A13,4)="2018",A13,""))
If you can view that last summary on a wide window, it should be able to see how the differing results for the other 39 results are achieved from the formula
Just to make clear once again what seems to go on in these sort of Evaluate formulas, in the next post is a table showing the actual Evaluateions done by VBA
_._____
_2 The final part of Rick’s solution is
Range("A1:A" & LastRow).SpecialCells(xlBlanks).EntireRow.Delete
This uses the VBA SpecialCells Method to get at the cells with nothing in them. Those are then deleted
Explanation:
VBA SpecialCells Method ( https://www.mrexcel.com/forum/excel-...onditions.html , https://docs.microsoft.com/en-us/off...e.specialcells ) returns you a range object ( that range object must not be contiguous ( connected ) cells ) consisting of those cells meeting a specific characteristic. We can choose from a number of characteristics. Here we choose xlBlanks , which refers to the characteristic of the cell being empty. So, if we applied that .SpecialCells(xlBlanks) to this range:.._
Row\Col B 9 10 112018, 1, 90515, 10024515, G9, SBlabla (HQ), CHE, BLABLA, blabla, 10012098, 12003.5 122018, 1, 90629, 10022334, P3, BLABLA blabla (blablabla), CHE, BLABLA,blabla, 10033609, 13941.72 132018, 1, 90709, 10020009, P4, Blabla og Blalala (NY), CHE, Blabla,Bla-ah, 10006098, 15392.64 14 152018, 1, 90765, 10012123, P4, Ch of Blabla(Blabla of Blabla), CHE, BLA-BLA,Bla Blabla, 10005678, 16231.7
_ … then the returned range from that would be Range(“B9:B10,B14”).
If we then apply .Delete to that range then those cells are removed. If you remove a cell via .Delete then initially there is a real hole, like a “black hole” that can’t really exist in a spreadsheet. So Excel might explode or implode, or you would be sucked into that hole , never to return!!! To prevent that happening, Excel shifts all cells to close that hole, ( and adds a new virgin cell at the bottom or right side to fill the indent there caused by the shift. The default Delete option for the direction of that shift is in our case upwards. Hence after applying the .Delete after applying .SpecialCells(xlBlanks) to the above range, we will be left with
Row\Col B 92018, 1, 90515, 10024515, G9, SBlabla (HQ), CHE, BLABLA, blabla, 10012098, 12003.5 102018, 1, 90629, 10022334, P3, BLABLA blabla (blablabla), CHE, BLABLA,blabla, 10033609, 13941.72 112018, 1, 90709, 10020009, P4, Blabla og Blalala (NY), CHE, Blabla,Bla-ah, 10006098, 15392.64 122018, 1, 90765, 10012123, P4, Ch of Blabla(Blabla of Blabla), CHE, BLA-BLA,Bla Blabla, 10005678, 16231.7 13 14
What has happened there is the following: Those empty cells ( which were yellow ) have been removed. Other cells have been shifted up to fill up the “holes” created by the removal
_.______________________________________________
Just to make clear once again what seems to go on in these sort of Evaluate formulas, in the next post is a table showing the actual Evaluateions done by VBA
Continued from last post
In a range evaluate type code line like the one we are considering, Excel VBA seems to do the following ( simplified )
Excel will have an output “window” ( this could be considered as an output table or output array ). The dimensions of this will be that rectangle that allows all used ranges in the formula to be fitted in,
There are some complicated ways in which Excel handles the situation of ranges of varying size, ( http://www.excelfox.com/forum/showth...on-and-VLookUp ) but for a simpler case of all ranges having the same size, ( in terms of “width” and “depth” ) , as we have, Excel VBA will “expand” its “output window” to this sort of thing:
Excel VBA will do its normal “along the columns, down a row, along the columns…” type thing, in any “Evaluation run”. In our case this will mean that it does an evaluation at each row, going down the rows. This is what Excel VBA does in order to fill that last window of cells, ( I am just showing the first 7 of 40 similar formulas as the full list is to big to fit in a forum post )
=IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A2," ",""),",","")),IF(LEFT(A1,4)="2018",TRIM(A1&" "&A2),""),IF(LEFT(A1,4)="2018",A1,"")) =IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A3," ",""),",","")),IF(LEFT(A2,4)="2018",TRIM(A2&" "&A3),""),IF(LEFT(A2,4)="2018",A2,"")) =IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A4," ",""),",","")),IF(LEFT(A3,4)="2018",TRIM(A3&" "&A4),""),IF(LEFT(A3,4)="2018",A3,"")) =IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A5," ",""),",","")),IF(LEFT(A4,4)="2018",TRIM(A4&" "&A5),""),IF(LEFT(A4,4)="2018",A4,"")) =IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A6," ",""),",","")),IF(LEFT(A5,4)="2018",TRIM(A5&" "&A6),""),IF(LEFT(A5,4)="2018",A5,"")) =IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A7," ",""),",","")),IF(LEFT(A6,4)="2018",TRIM(A6&" "&A7),""),IF(LEFT(A6,4)="2018",A6,"")) =IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A8," ",""),",","")),IF(LEFT(A7,4)="2018",TRIM(A7&" "&A8),""),IF(LEFT(A7,4)="2018",A7,""))
Excel VBA will effectively make 40 formulas and place in the “output window” the result of the evaluation of those formulas
The full demo code in the next post includes a code line to put in all 40 formulas in an arbitrary 40 “deep” x 1 “wide” range ("J5:J44")
A Folk, A Forum, A Fuhrer ….
Full demo code to accompany last post:
Code:Option Explicit Sub ThisShouldWork() Dim LastRow As Long, strEval As String Let LastRow = Cells(Rows.Count, "A").End(xlUp).Row Let strEval = Replace(Replace("IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A2:A#,"" "",""""),"","","""")),IF(LEFT(A1:A@,4)=""2018"",TRIM(A1:A@&"" ""&A2:A#),""""),IF(LEFT(A1:A@,4)=""2018"",A1:A@,""""))", "#", LastRow + 1), "@", LastRow) Debug.Print strEval ' Hit Ctrl+g from the VB Editor to get the Immediate window up. 'IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A2:A41," ",""),",","")),IF(LEFT(A1:A40,4)="2018",TRIM(A1:A40&" "&A2:A41),""),IF(LEFT(A1:A40,4)="2018",A1:A40,"")) 'This is the spreadsheet equivalent to Rick's Evaluate Range("B1:B" & LastRow).FormulaArray = "=" & strEval 'This gives a demo of the actual formulas that Excel VBA does Range("J5:J44").Value = "=IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A2,"" "",""""),"","","""")),IF(LEFT(A1,4)=""2018"",TRIM(A1&"" ""&A2),""""),IF(LEFT(A1,4)=""2018"",A1,""""))" ' Applying the fixed vector notation (Excel instructed to do that by no $s) will result in the same relative formula. Displayed will be the actual formula ( in the relative form, but that is not important) ' Final solution Rick : http://www.excelfox.com/forum/showth...0888#post10888 Range("A1:A" & LastRow) = Evaluate(Replace(Replace("IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A2:A#,"" "",""""),"","","""")),IF(LEFT(A1:A@,4)=""2018"",TRIM(A1:A@&"" ""&A2:A#),""""),IF(LEFT(A1:A@,4)=""2018"",A1:A@,""""))", "#", LastRow + 1), "@", LastRow)) ' Range("A1:A" & LastRow).SpecialCells(xlBlanks).EntireRow.Delete ' This will mess up now due to my .FormulaArray as you can't delete bits of that End Sub ' 2018, 1, 90709, 10020009, P4, Blabla og Blalala (NY), CHE, Blabla,Bla-ah, 10006098, 15392.64 ' TRIM(A13" "&A14) ' IF( True , TRIM(A13" "&A14) , A13 ) ' IF( ISNUMBER(0+1000609815392.64), TRIM(A13" "&A14) , A13 ) ' IF( ISNUMBER(0+SUBSTITUTE(10006098,15392.64),",","")), TRIM(A13" "&A14) , A13 ) ' IF( ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")), TRIM(A13" "&A14) , A13 ) ) ' IF( ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")), IF(LEFT(A13,4)="2018" , TRIM(A13" "&A14) , "") , IF( LEFT(A13,4)="2018" , A13 ,"" ) ) ' IF( ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")), IF(LEFT(A13,4)="2018" , TRIM(A13" "&A14) , "") , IF( LEFT(A13,4)="2018" , A13 ,"" ) ) ' IF( ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")),IF(LEFT(A13,4)="2018",TRIM(A13" "&A14),"") , IF(LEFT(A13,4)="2018",A13,"") ) ' IF(ISNUMBER(0+SUBSTITUTE(SUBSTITUTE(A14," ",""),",","")),IF(LEFT(A13,4)="2018",TRIM(A13" "&A14),""),IF(LEFT(A13,4)="2018",A13,""))
A Folk, A Forum, A Fuhrer ….
Bookmarks