Convert long formula into an ARRAYFORMULA - excel-formula

Document: https://docs.google.com/spreadsheets/d/1N4cGw5eUq_3gCJh1w39qVatX9KV1_Hr-AqRHj_nbckA/edit#gid=1770960621
Question
How can I convert the following simple formulas at Schedule!C20:I29 into a single, simple ARRAYFORMULA at Schedule!C20?
=Count(Filter(Students!$B$5:$B, Find(C6, Filter(Students!$J$5:$O,Students!$J$4:$O$4 = 'Current Class'!$B$3))))
.
NOTE:
The above code is only a partial solution. I will substitute the ARRAYFORMULA version of the code into the correct part of the code at Current Class!L6
The C6 reference above can take on any cell between Schedule!C6:I15. I have named that range Timetable_Code. I thought I could do the following, but I was wrong...
=Arrayformula(Count(Filter(Students!$B$5:$B, Find(Timetable_Code, Filter(Students!$J$5:$O,Students!$J$4:$O$4 = 'Current Class'!$B$3)))))
Background
Originally, I created a table that now resides at 1st Version - Current Class!L6. This tab is only for your reference and will be deleted soon. Each cell has a formula with a slight modification. This formula works correctly; however, it is a behemoth and would be hard to modify...
=if(COUNTIF(Meta!$B$5:$B, CONCATENATE("=",if(L$5 = "THURSDAY", "TH", if(L$5 = "SUNDAY", "SU", left(L$5,1))), if(left($K6, 2) = "12", 0, left($K6, 1)))), CONCATENATE(if(L$5 = "THURSDAY", "TH", if(L$5 = "SUNDAY", "SU", left(L$5,1))), if(left($K6, 2) = "12", 0, left($K6, 1)), " ( ", Count(Filter(Students!$B$5:$B, Find(CONCATENATE(if(L$5 = "THURSDAY", "TH", if(L$5 = "SUNDAY", "SU", left(L$5,1))), if(left($K6, 2) = "12", 0, left($K6, 1))), Filter(Students!$J$5:$O,Students!$J$4:$O$4 = $B$3)))), " )") ,"")
.
Pros
I don't have to create any helper data.
All calculations are "in-memory"
Cons
Too large
Hard to modify
I like the output, but I don't like the cons, so I started to create a more edit-friendly version of the code that I am mostly OK with. This code is located at Current Class!L6 (and a secondary copy at Schedule!C33 - it will be deleted.) It has a single formula at Current Class!L6...
=arrayformula(if(COUNTIF(Meta!$B$5:$B, ("=" & Timetable_Code)), (Timetable_Code & " ( " & Timetable_StudentCount & " )") ,""))
.
Pros
Very easy to understand
Very easy to modify
No need to copy formula over to other cells
Cons
Two ( 2 ) helper tables were created ( one of which I think is unneeded)
Again, I like the output, but I really don't like the second helper table (Schedule!C20). I feel like this table can be eliminated, but I have not been able to figure out how.

If you really want to use arrayformula, here it is. For Schedule!C20.
=arrayformula((len(concatenate(index(Students!J5:O, , match('Current Class'!$B$3, Students!J4:O4, 0))))-len(substitute(concatenate(index(Students!J5:O, , match('Current Class'!$B$3, Students!J4:O4, 0))),C6:I15,"")))/len(C6:I15))
Probably you can use filter(as you did before) instead of index & match part, but I prefer index & match and don't want to dig more. Also you can use one help cell to store filter or index & match result to shorten the formula.
The core idea is from counting occurrences of given character in a string, ie len(a1) - len(substitute(a1, .... You can find many documents about it in the net.
Anyway, if I were you, I'd be satified with the current state. Just lock and hide the help tables or sheets. Nobody cares hidden sheets and if something bad happens, you can revert any change.

After getting a good answer from #Sangbok Lee, I decided to break apart each part of the function he gave to me. While doing that I found a highly unlikely connection to some work I did in the Google Sheets last week. A helper column I had in another tab kind of did what Sangbok Lee was trying to do. All I had to do was split that helper column into two columns (1 for the previous final calculation, 1 for) and calculate an additional count column
After reworking both of our formulas, and testing the result, I found a solution that I am even more satisfied with!
=arrayformula(if(countif(Meta!$B$5:$B, (Timetable_Code)), (Timetable_Code & " ( " & vlookup(Timetable_Code, StudentCount_Lookup, 2, false) & " )") ,""))
.
Check out the differences in the Google Sheet
Look at 1st Version - Current Class!L6 tab for the 1st version
Look at Current Class!L6 for the 2nd version
Look at Current Class!U6 for the 3rd and final version
Also look at tab Meta and Schedule for the differences.
Note: Green is old data, Red is new data

Related

Clean data in excel that comes in varying formats

I have an excel table that contain values in these formats. The tables span over 30000 entries.
I need to clean this data so that only the numbers directly after V- are left. This would mean that when the value is SV-51140r3_rule, V-4407..., I would only want 4407 to remain and when the value is SV-245744r822811_rule, I would only want 245744 to remain. I have about 10 formulas that can handle these variations, but it requires a lot of manual labor. I've also used the text to column feature of excel to clean this data as well, but it takes about 30 minutes to an hour to go through the whole document. I'm looking for ways that I can streamline this process so that one formula or function can handle all of these different variations. I'm open to using VBA but don't have a whole lot of experience with it and I am unable to use Pandas or any IDE or programming language. Help please!!
I've used text to columns to clean data that way and I've used a variation of this formula
=IFERROR(RIGHT(A631,LEN(A631)-FIND("#",SUBSTITUTE(A631,"-","#",LEN(A631)-LEN(SUBSTITUTE(A631,"-",""))))),A631)
Depending on your version of Excel, either of these should work. If you have the ability to use the Let function, it will improve your performance, as this outstanding article articulates.
If you're on a really old version of excel, you'll need to hit ctl shift enter to make array formula work.
While these look daunting, all these functions are doing is finding the last V (by this function) =SUBSTITUTE(RIGHT(SUBSTITUTE(A2,"V",REPT("πŸ„",999)),999),"πŸ„","") and then looping through each character and only returning numbers.
Obviously the mushroom πŸ„ could be any character that one would consider improbable to appear in the actual data.
Old School
=TEXTJOIN("",TRUE,IF(ISNUMBER(MID(MID(SUBSTITUTE(RIGHT(SUBSTITUTE(A2,"V",REPT("πŸ„",999)),999),"πŸ„",""),
FIND("-",SUBSTITUTE(RIGHT(SUBSTITUTE(A2,"V",REPT("πŸ„",999)),999),"πŸ„","")),9^9),
FILTER(COLUMN($1:$1),COLUMN($1:$1)<=LEN(MID(SUBSTITUTE(RIGHT(SUBSTITUTE(A2,"V",REPT("πŸ„",999)),999),"πŸ„",""),
FIND("-",SUBSTITUTE(RIGHT(SUBSTITUTE(A2,"V",REPT("πŸ„",999)),999),"πŸ„","")),9^9))),1)+0),
MID(MID(SUBSTITUTE(RIGHT(SUBSTITUTE(A2,"V",REPT("πŸ„",999)),999),"πŸ„",""),
FIND("-",SUBSTITUTE(RIGHT(SUBSTITUTE(A2,"V",REPT("πŸ„",999)),999),"πŸ„","")),9^9),
FILTER(COLUMN($1:$1),COLUMN($1:$1)<=LEN(MID(SUBSTITUTE(RIGHT(SUBSTITUTE(A2,"V",REPT("πŸ„",999)),999),"πŸ„",""),
FIND("-",SUBSTITUTE(RIGHT(SUBSTITUTE(A2,"V",REPT("πŸ„",999)),999),"πŸ„","")),9^9))),1),""))
Let Function
(use this if you can)
=LET(zText,SUBSTITUTE(RIGHT(SUBSTITUTE(A2,"V",REPT("πŸ„",999)),999),"πŸ„",""),
TEXTJOIN("",TRUE,IF(ISNUMBER(MID(MID(zText,FIND("-",zText),9^9),
FILTER(COLUMN($1:$1),COLUMN($1:$1)<=LEN(MID(zText,FIND("-",zText),9^9))),1)+0),
MID(MID(zText,FIND("-",zText),9^9),
FILTER(COLUMN($1:$1),COLUMN($1:$1)<=LEN(MID(zText,FIND("-",zText),9^9))),1),"")))
VBA Custom Function
You could also use a VBA custom function to accomplish what you want.
Function getNumbersAfterCharcter(aCell As Range, aCharacter As String) As String
Const errorValue = "#NoValuesInText"
Dim i As Long, theValue As String
For i = Len(aCell.Value) To 1 Step -1
theValue = Mid(aCell.Value, i, 1)
If IsNumeric(theValue) Then
getNumbersAfterCharcter = Mid(aCell.Value, i, 1) & getNumbersAfterCharcter
ElseIf theValue = aCharacter Then
Exit Function
End If
Next i
If getNumbersAfterCharcter = "" Then getNumbersAfterCharcter = errorValue
End Function

How do you look for a condition in a range and then get info from another range into a single cell?

So at the moment I have a working code to get multiple items in a cell following a condition
My code is:
=Contatenate(
IF('Sheet1'!E3 = "R",'sheet1'!A3,""), " ",
IF('Sheet1'!E4 = "R",'sheet1'!A4,""), " ",
and so on.....
it then returns every name that meets this condition.
I was just wondering if there was a quicker way to do this.
Thanks!
Leaving the solution as an answer to make it more clear:
=ArrayFormula(TEXTJOIN(" ",TRUE,IF('Contact & Overview'!E103:E122="R",'Contact & Overview'!A103:A122,"")))
From Sheets TEXTJOIN:
Sample Usage
TEXTJOIN(β€œ β€œ, TRUE, β€œhello”, β€œworld”)
TEXTJOIN(β€œ, ”, FALSE, A1:A5)
Syntax
TEXTJOIN(delimiter, ignore_empty, text1, [text2, ...])

Excel table names contain a '$' when pulled from a schema in VB.net

I have a list box that I'm trying to populate in an application to contain Excel tab names or Access tables. It's created by a simple schema grab:
dtSheet = OpenCon.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, New Object() {Nothing, Nothing, Nothing, "TABLE"})
It then gets put into a simple list (of String):
For Each Row In dtSheet.Rows
ListOfSheets.Add(Row("TABLE_NAME").ToString())
Next
This works fine if I open up an Access database, the names of the tables are listed nicely. However, when I use it for Excel, I get symbols such as $ and quotes "'". I'd like to trim this off to just have the tab names but so far I haven't been able to find anything to help my issue specifically.
My suspicion is that the answer is in the {Nothing...."TABLE"} object. I'm a little light on how filters like this work and I was having issues wrapping my head around it after reading the .NET documentation.
Another idea would be to do some post string alteration trimming but I'd like to see if there was an easier way to get the simple string name that I want from the start.
Any help would be appreciated.
Based on the discussion from jmcihinney, I built a slightly better code.
dtSheet = OpenCon.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, New Object() {Nothing, Nothing, Nothing, "TABLE"})
dtSheet.Columns.Add("Table_Text", Type.GetType("System.String"))
For i As Integer = dtSheet.Rows.Count - 1 To 0 Step -1
If Microsoft.VisualBasic.Strings.Right(dtSheet.Rows(i)("TABLE_NAME"), 1) <> "$" Then
dtSheet.Rows.RemoveAt(i)
Else
dtSheet.Rows(i)("TABLE_Text") = Replace(dtSheet.Rows(i)("TABLE_NAME"), "$", "")
End If
Next
I essentially add a column to the datatable that is built from the list pull. To remove anything that isn't a table (e.g. named ranges, Sheet views) I check the Table_Name column for the suffix of "$". Note I go backwards to keep from messing with any indexing.
Then in the Else statement I put a "Replace" to make the table_text a "$"less version of Table_Name
That way I can then build my listbox like this:
Me.lbTableList.DataSource = dtsheet
Me.lbTableList.DisplayMember = "TABLE_Text"
Me.lbTableList.ValueMember = "TABLE_NAME"
This makes my table look nice regardless if I loaded an Access database or Excel file. This also allows me to just pass the TABLE_NAME to the connection command and not worry whether there is a "$" in the name or not:
DBCmd.CommandText = "SELECT * FROM [" & strTable & "]"

Comparing Textbox value to cell value

I programmed a communication tool for the production floor. This tool will register what they have done, who has done it and on what time.
The following should check whether the textbox value equals the value in the worksheet or if the textbox (textbox is TextTools1) is empty. If this is true, then nothing should happen and the thus the value of the textbox is gonna stay the same.
If the textbox is not empty or is not equal to what has been previously saved in the worksheet (thus the value has changed), then it should be registered which operator has done it and what date and what time.
It works when the textbox is empty, but when the value of the textbox has stayed the same (thus TextTools.value=ActiveCell.Offset(0,23).value (Correct)) it still adds the operators name, date and time.
Something is going wrong when trying to compare the textbox value and the cell value, but cant put my finger on it.
Sheets("Checklist & overdracht").Visible = True
Sheets("Checklist & overdracht").Select
If TextTools1.Value = Range("AZ1").Value Or TextTools1.Value = Empty Then
Sheets("Checklist & overdracht").Select
rowloc1.Value = ActiveCell.Row
ActiveCell.Offset(0, 23).Value = TextTools1.Value
Else
Sheets("Checklist & overdracht").Select
rowloc1.Value = ActiveCell.Row
ActiveCell.Offset(0, 23).Value = TextTools1.Value & " " & "(" & cboOperator.Value & " " & Format(DateValue(CStr(Now)), "short date") & " " & Format(TimeValue(CStr(Now)), "hh:mm") & ")"
End If
Edit; changed it to the code above. I tested this in another userform (and used f8) and it works brilliantly, but when I put in the userform that will actually run this code, than it doesnt have the same result...
Edit2; So apparently something goes wrong with Range(AZ1).Value reference. Because when I enter a random value instead of the range and then run the code, it does work. Is there a different way of referencing?
Ok based on your comments
Stop using active cell when code from a user form is communicating to the compiler what sheet is what. You need to fully qualify what sheet you are using. Im not entirely sure where in the code the active sheet is being set but I am fairly certain the answer is never. Another reason selecting and referencing .ActiveWhatever is bad is a cardinal sin of vba is interacting with the actual application object instead of doing everything in memory. It bogs everything done and performance suffers considerably. When you start writing pretty dense stuff then you will inevitably suffer from issues where the compiler gets confused as to what thing it should be looking at and you'll have a grand ol' time of troubleshooting that nonsense.
Also, it might be a good idea to check for more than just "=Empty". What if there is a null or empty string? I tend to check for:
.value = "" OR ISNULL(.Value)=True OR .Value = vbNullstring
this isnt real feedback though - tons of people have different ways of doing the same thing.
Try:
Thisworkbook.Sheets("YOURSHEETNAME").Range("YOURRANGE").Offset(0,23).Value = Someothervalue.
Let me know if youre still facing issues.

VB Macro Like Operator

I am very new to VB macro.In sheet 3 i have three columns named "Country " "Provinces" and "Risk"
For "Provinces", values present are NB,NS,NF,PE. IN sheet5, i have written a code like
`(val) Like "*[HH,HHJ,qqw,www]" Then
to check if user has provided input like NB or like NB, NS or like PE only then corresponding values from Risk will get displayed. Now with the above code , if user is entering value as "," also results is getting displayed as , is present in the Like statement.
Kindly guide me.
You can't use VBA Like that way. Try:
X = "abc, NB"
If X Like "*NB" Or _
X Like "*NS" Or _
X Like "*NF" Or _
X Like "*PE" Then
Debug.Print "X is in the Maritimes"
End If
If you set Option Compare Text at the beginning of your macro, you don't have to Ucase the string being tested.
For complex comparisons, you can use Regular Expressions in VBA. You need to set the appropriate reference.

Resources