Sort strings alphabetically ignoring brackets - vba

I have eight different variables that can have a value or no value. They look something like this:
A= "h"
B= "(z)"
C= "a"
D= ""
E= "[st]"
F= ""
G= "xx"
H= "(t)"
I need them all together in alphabetical order (must include the brackets):
Aim= "a,h,[st],(t),xx,(z)"
I know how to put them in one string and how to put the "," in the right place.
How do I put them in alphabetical order, while ignoring the brackets?
To exclude the emtpy values and add the commas I use for every value:
If IsEmpty(HH) = False Then HHH = HH.Value & ","
To put them together I use the "&" function
StrHoribez = BBB & CCC & DDD & EEE & FFF & GGG & HHH & III
To remove the last comma I use:
If Right$(StrHoribez, 1) = "," Then StrHoribez = Left$(StrHoribez, Len(StrHoribez) - 1)
The alphabetical sorting can happen in between any of these steps.
How can I approach this? Maybe something with an array but I have no experience using these.

Using Excel worksheet:
Put the values into column A
Put the clean values without brackets into column B
Sort on the values in column B
Retrieve the sorted values from column A including the brackets
Using two-dimensional array:
Put the values into arr(x, 0)
Put the clean values without brackets into arr(x, 1)
Sort on the clean values
Retrieve the sorted values from arr(x, 0) including the brackets
See this for multi-dimensional sorting:
Sorting a multidimensionnal array in VBA

Related

Matching 2 columns with 2 others columns to return a value from another column

I have an issue I'm trying to fix in excel.
I want to create an automation with the following logic:
-Lookup each value from column H and I
-If they match the values in column A and B respectively
-Return the value in C to column J.
** Basically, IF(((H=A) AND (I=B)) THEN (return C in J)) ****
How is that possible?
In J2:
=IF(AND(H2=A2, I2=B2), C2, "")
In J2 this array formula:
=INDEX($C$2:$C$100,MATCH(H2 & "|" & I2,$A$2:$A$100 & "|" & $B$2:$B$100,0))
Being an array formula it needs to be confirmed with Ctrl-Shift-Enter instead of Enter when exiting edit mode. If done correctly Excel will put {} around the formula.
So enter in J2. Hit Ctrl-Shift-Enter. Then copy down.

Variable number of terms in an Excel VBA Formula?

Is it possible to write a formula in VBA for excel such that there are "n" terms in the formula, with the number of terms changing as the value of "n" does?
For instance, say you wanted to code cell a1 such that it was the sum of a2 and a3. Then you wanted b1 to be the sum of b2,b3,b4,b5 and so on such that each column 1 row 1 cell for a range of cells is the sum of "n" cells below it where "n" varies from column to column. Say that all cell addresses you wanted to use are known and stored in an array.
Here is some code to better explain what I'm asking:
For i = 0 to n
Range(arr1(i)).formula = "=" & range(arr2(i)).value & "-(" _
& Range(arrk(i)).value & "+" & Range(arrk+1(i)).value & "+" _
& Range(arrk+2(i)).value & "+" & ... & ")"
Next i
So what I'm looking for is one piece of VBA code that can make a cell formula contain a dynamic number of terms. The code above would make cell a1's value = a-(b+c+d+...) where the number of terms in the bracket is variable, depending on which cell the formula is applied to.
The image here shows an example of what I want to do. I'd like some code which could take "years income" and subtract a variable amount of "expenses" from it, where the number of expenses varies each year (but the number stays fixed for that year). The code needs to use a formula so that the expenses entries can be modified by the user.
Have you tried Array Formula ? :
Array Formula :
An Excel Array Formula performs multiple calculations on one or more sets of values (the 'array arguments') and returns one or more results.
details : http://www.excelfunctions.net/Excel-Array-Formulas.html
Thanks for the suggestions everyone, I found a solution (not a particularly efficient one, but a solution nonetheless) to the conundrum today.
First I created an array which used the "pattern" of the Junk cells to list every cell address which was to be included.
Taking this array, I used a for loop to create a series of temporary arrays with the application.index command. For each temporary array, I used the Join command to turn the list of cells into a single string which I then inputted into a cell formula. Thanks to #thepiyush13 whose array.formula approach inspired this.
Here's some example code to show what I did:
' hypothetical array containing two sets of cells to use
Dim array1(0 To 1, 0 To 1) As Variant
Dim vartemp As Variant
Dim vartemptransposed As Variant
' col 1 will be used to add I10 and I13, col2 I11 and I14
array1(0, 0) = "$I$10"
array1(1, 0) = "$I$13"
array1(0, 1) = "$I$11"
array1(1, 1) = "$I$14"
For i = 1 to 2
'application.index(arr,row#,col#) to create a new array
vartemp = Application.Index(array1, 0, i)
'error if not transposed
vartemptransposed = Application.Transpose(vartemp)
randomstring = Join(vartemptransposed, ",")
totalvalue = 100
'example formula: a1 = totalvalue - sum(I10,I13). a2 = totalvalue - sum(I11,I14)
Cells(1,i).formula = "=" & totalvalue & "-SUM(" & randomstring & ")"
Next i
I needed the code to run this many many times on large lists which are generated dynamically but always hold the same pattern of where the "junk cells" are. Not included in the code, but I also used another array for the cell addresses of where to place the formula.

Pad single-digit numbers with a zero

I have a loop like this to save sheets as CSV files but my first 9 sheets are name liked sinani-01 ... sinani-09 (not like sinani-1 ... sinani-9). How I can concatenate a 0 only before numbers less than 10?
Sub Adder()
Dim animal As String
Dim i As Integer
For i = 1 To 120
animal = "sinani-" & i
Sheets(animal).SaveAs "E:\Data\CSV\" & animal & ".csv", xlCSV
Next i
End Sub
VBA has a Format() function that you can use to pad numbers.
animal = "sinani-" & Format$(i, "00")
This will pad single-digit numbers with a 0. Your two- and three-digit numbers will continue to work as expected.
In the fifth line use the Format function like this:
animal = "sinani-" & Format(i, "#00")
The # means optionally a digit (i.e. present only if there are that many digits in i), 0 means definitely a digit, whereby leading zeros are used if i hasn't got enough digits.
Concatenate with a leading series of zeroes and peel off as many digits from the right-hand side as you need.
animal = "sinani-" & Right("00" & i, 2)
'alternate for many leading zeroes (e.g. DUNS number)
animal = "sinani-" & Right(String(9, "0") & i, 9)
Replace & i by & IIF(i < 10,"0","") & i
On edit: Even though in this case Format provides a cleaner solution than IIF, the IIF trick has some other uses in tweaking output. For example, if you wanted to inform the user how many cells were found which satisfy some condition you could use something like
MsgBox n & "cell" & IIF(n <> 1,"s","") & " found"
to gracefully handle plural vs. singular endings

How to parse this specific type of data in excel VBA?

I have a bunch of different sets of engineering measurements in the format:
77.170 (+/- 0.025)
And I need to split it into the first number, which is the nominal value, and the number in the parenthesis, the tolerance. Not sure exactly how to do this in excel VBA. I was thinking I would use the Split function with a space delimiter, giving me the first number, then the unnecessary characters, then the tolerance, but the tolerance will include a parenthesis. How could I get rid of just that parenthesis, and will what I just suggested even work? Thanks!
Consider:
Sub dural()
s = "77.170 (+/- 0.025)"
s2 = Replace(Replace(Replace(s, " ", ""), "+/-", ""), ")", "")
ary = Split(s2, "(")
MsgBox ary(0) & vbCrLf & ary(1)
End Sub
Use Text to Columns and a formula.
Go to Data--->Text to Columns. Choose delimited and choose Space as your delimiter. This should split the text string into something like:
ColA |ColB|ColC
77.170|(+/-|0.025)
Column C is a bit funky, so let's just grab everything but the last character.
In column D put this:
=LEFT(C1,LEN(C1)-1)
Finally, you should get:
ColA |ColB |ColC |ColD |
77.170|(+/- |0.025)|0.025|
I would use a combination of instr() and mid to get what you need. For example
measurments="77.170 (+/- 0.025)"
mid(measurements,1,instr(measurements," "))
trim(mid(measurements,instr(measurements,"-")+1,instr(measurements,")")-instr(measurements,"-")-1))
or, to combine,
measurments="77.170 (+/- 0.025)"
mid(measurements,1,instr(measurements," ")) & " " & trim(mid(measurements,instr(measurements,"-")+1,instr(measurements,")")-instr(measurements,"-")-1))
Try using a combination of InStr(), Left(), Right().
Get the index/position of the '(' using InStr and then extract the characters using Left and Right. If you want to get the final data as a double or a Long use CDbl() or CLng() respectively.
For getting text out of other text consider using Regular Expresions.
To use them in VBA you will need in Reference 'VBScript_RegExp_55' library.
The reason why you might want to do that is because following code returns whatever first two numbers show up in your text( it can be modified to be much smarter than that), regardless of other text around it.
Dim Regex As RegExp
Dim Matches As MatchCollection
Set Regex = New RegExp
Regex.Pattern = "\d*\.\d*"
Regex.Global = True
Set Matches = Regex.Execute("77.170 (+/- 0.025)")
MsgBox (Matches(0).Value & " " & Matches(1).Value)
Assuming s is your measurement string, here is the most direct way:
v = Split(Left(s, Len(s) - 1), " (+/- ")
That's it. Now v(0) holds the nominal value and v(1) holds the tolerance.

Select everything to the right of a specific character and delete it from column

My column S needs to only contain one word, however, on import it usually has about three words separated by commas. I would like to only keep the first word in the cell.
For example, my S1 column has something like "x, y, z" and I would like to make S1 only say x. So basically, I am trying to remove everything to the right of the first comma in the cell. I have tried to use Replace, but that isn't working. Is there a simpler way to do this?
My (failing) macro right now:
For i = ActiveSheet.UsedRange.Rows.Count To 1 Step -1
If Cells(i, 19) = "," Then Columns("S:i").Select
Selection.Replace What:=Trim(Right(ActiveCell.Value, 25), InStr(ActiveCell.Value, ",") - 1), Replacement:=""
Next
What you are looking for is a Split function.
It works like this:
Dim str As String: str = "x, y, z"
Debug.Print Split(str, ",")(0)
Result is x
The important parameters for Split are string and delimiter, the number after the function specifies the occurence. So if you wanted to select y, you would put 1 there etc. In that case, you would probably include the space in the delimiter so you would not need to trim the result further.
You can use left with Instr to give you all the characters before the first comma.
ActiveCell = Left(ActiveCell,Instr(ActiveCell,",")-1)
Thanks to #pnuts I was able to complete this task. I was unaware that wildcards could be used in Replace. This is my (working) macro:
Columns("S:S").Replace What:=",*", Replacement:=""