Excel macro to normalize data - vba

I am currently trying to create a macro for Excel in which a column containing certain values (numbers basically) will be displayed in a new column in a normalized way (highest number = 1, lowest number = 0).
Usually, I would just use the formula:
=(J2-MIN($J$2:$J$XXX))/(MAX($J$2:$J$XXX)-MIN($J$2:$J$XXX))
However, as the length of the column is dynamic and will change for each set of values, I cannot enter a value for XXX.
Now, I found out how to have a dynamic range (e.g.: numRows = Range(Selection, Selection.End(xlDown)).Rows.Count) but I did not manage to merge both functions.
I found a thread already in this site about normalization of data but I think it was a bit of a different story and this one here should be simpler.
I would appreciate any help! As I just started working with macros (2h ago) I would also appreciate if this will be in simple language.
EDIT:
First of all, thanks for the quick reply!
I naively tried making it work with this code:
Sub Normalize_TEST()
'
' Normalize_TEST Makro
'
'
Range("A1").Select
numRows = Range(Selection, Selection.End(xlDown)).Rows.Count
Range("K2").Select
ActiveCell.FormulaR1C1 = "=(("J2")-MIN($J$2:$J$numRows$))/((MAX($J$2:$J$numRows$)-MIN($J$2:$J$numRows$))
Range("K2").Select
Selection.AutoFill Destination:=Range(Cells(2, 11), Cells(numRows, 11))
End Sub
But it is not working and I get an error message ("error of compiling").

I just realize now that you are absolutely right, I don't even need VBA. Your line of =(J2-MIN($J:$J))/(MAX($J:$J)-MIN($J:$J)) works fine. I wasn't aware that with $j:$J it realizes to not include empty cells.
I simply used this code now for cell K2 and then did a VBA autofill function for the rest.
I think this can be closed.
Thank you #tigeravatar for your super quick help!

Related

Drag down formula from last row with formula to next, until "A" ends

My problem is that i have big Excel file and need to drag down formulas as i copy values, I explain it further with an example table:
I have a vba script running in the background that on execution copys missing data from another datasheet, this copy procedure is in a For Each and in there i want to also copy down the formulas from the last row where there are formulas from the Range D:F.
For those who want to see it, this is my copy function:
If rowNotFoundMain = True Then
If cell2.Offset(0, 7).Value = 0 Then ' Offset 7, sind die Ehrungen
cell2.Interior.Color = vbYellow
Else
Set rFirstBlank = ws1.Cells(ws1.Rows.Count, 1).End(xlUp).Offset(1)
ws2.Range(cell2.Address, cell2.Offset(0, 2).Address).Copy
rFirstBlank.PasteSpecial
' INSERT DRAG DOWN FUNCTION HERE '
End If
End If
I looked up various ways on the Internet but didn't find suitable answers for my problem.
Why am I asking this directly for an answer and can't help anyhow ? Simple, I can program in theory but never used VBA, my boss wants this from me and I am searching everything together from the web.
I hope my explanation makes sense and if you need further Information, please don't hesitate and ask away.
Have a nice week!
Select D2:F6 range
Double-click black square in the bottom right hand side corner
Your formulas are copied!
Now do the same while recording a macro
Check recorded result and adopt to your case.

Autofill in Excel VBA returns error 1004

I am trying to get a raw Excel file into a customized format. I added a picture below, so its easier to explain. I will address the requirements as steps too.
1) I need to get rid off all columns which include "Importo" or "Prezzo"
2) I need to extract the date from the remaining columns (Quantitá). First, I insert an empty row on top and then i apply right(cell,7).
So far, so good.
Then I want to autofill the remaining columns, but i get a 1004 error. In the example code I tried from J:O, but really id need it from J to the last column. I post the code (which works until the last row).
I was actually wondering if Autofilling is best practise here, maybe indexing though would be better?
Sub delete_col()
Dim A As Range
Do
Set A = Rows(1).Find(What:="Importo", LookIn:=xlValues, lookat:=xlPart)
If A Is Nothing Then Exit Do
A.EntireColumn.Delete
Loop
Do
Set A = Rows(1).Find(What:="Prezzo", LookIn:=xlValues, lookat:=xlPart)
If A Is Nothing Then Exit Do
A.EntireColumn.Delete
Loop
Rows("1:1").Select
ActiveCell.EntireRow.Insert
ActiveCell.Range("J1").Select
ActiveCell.FormulaR1C1 = "=RIGHT(R\[1\]C,7)"
Selection.AutoFill Destination:=ActiveCell.Range("J1:O1"), Type:=xlFillDefault
End Sub
I suppose that in the line ActiveCell.FormulaR1C1 = "=RIGHT(R\[1\]C,7)", the \ is a kind of typo, which should be deleted.
Concerning the 1004 error, the easiest way to go around it, while doing AutoFill, is something like this:
Sub TestMe()
Range("A1:O1") = Range("J1")
End Sub
Thus, every value in Range("A1:O1") will be set with the value from Range("J1").
However, your code uses a lot of Select, Activate and ActiveCell. Try to avoid these, because they are not considered good practices in VBA and may lead to different errors. How to avoid using Select in Excel VBA

Looping the whole cells to change a specific formula issue

I'm writing a function to change an entire column to new values using a formula, here's the code I'll elaborate more on the idea down there.
The problem is that it hangs and I have to rerun Excel and I'm not sure why.
Sub Button2_Click()
Dim i As Long
For i = 2 To Rows.Count
Cells(i, 4).Formula = "=B" & i & "+6*3600000/86400000+25569"
Next i
End Sub
So what's this about? I'm changing the fourth column to excel time because what I have in column B is epoch time, and this is the formula I'm using, it works with my case if I tried one by one, but for some reason it won't work as a whole. I'm not sure what's done wrong? But I'd appreciate your help.
Writing to cells one-by-one is very slow.
Writing formulas one-by-one is slower still, because each must be evaluated before Excel accepts them as formulas.
Doing this a million times can literally freeze Excel.
The solution is to write them all in one shot (no loops):
Sub Button2_Click()
[d2:d1048576] = "=B2+6*3600000/86400000+25569"
End Sub
' Another way of doing mass calculation is by using copy and paste method.
It will be better to convert the columns into values so that the sheet won't calculate again and again. It helps to prevent the sheet from hanging issues
Sub Button2_Click()
Range("D2").Formula = "=b1" & "+6*3600000/86400000+25569"
Range("D2").Copy
Range("D2:d1048576").PasteSpecial xlValues
Application.CutCopyMode = False
Range("D:D").Value = Range("D:D").Value
End Sub

Using a function to return a value in VBA without using the worksheet

Good afternoon One and All,
I am relatively new to VBA and I am trying to use the Worksheet function, specifically the index function to look up information in the code and bring back a value. I would love to do this without having to assign it to a cell in the worksheet using R1C1. Is there a way to do Vlookups, or Indexex without having to make assignments in the worksheet?
The examples below works as an equation placed within the sheet, but I'd like to get the same answer without having to use the sheet.
The first formula looks up a Batch number
The second formula is finding the name of the first ingredient in the batch, based on the SKU in the worksheet.
ActiveCell.FormulaR1C1 = _
"=VLOOKUP(RC[-1],'U:\Files\Maintenance File.xls'!SKUinfo,16,FALSE)"
ActiveCell.FormulaR1C1 = _
"=INDEX('U:\Files\[Recipe File.xlsx]Fresh 2800'!Fresh2800,2,6)*(INDEX(SchedInfo,MATCH(RC[-3],SKULookup,0),6))"
Any help would be appreciated, and thank you for all your help in advance.
The answer to this Microsoft forum post describes what you want. Use the Application object:
ans = Application.VLookup(arg1, MyRange, arg3, arg4)

VBA help in selecting entire rows on a dynamic range

Hi thanks everyone in advance.
I have a data set. lets say A3 to Z30. the number of rows and columns varies. also there are blanks in the set. So lets say i want to select the entire section but there's a blank in Z29 and X30 using
Range("A3").Select
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
isn't going to work.
But the values in column A is continuous. So i think the first part will work
Range("A3").Select
Range(Selection, Selection.End(xlDown)).Select
now i know this may seem elementry but how the heck do i select all the rows i just highlighted? this needs to be dynamic because as i said the number of columns and rows vary.
Oh and bonus karma and kudos if you can help me to figure out the next part. I need to select the range and paste it immediately after the the last row but the value in the first cell or A31 in this case would need to change and that is being pulled from a list in sheet2
Use the .EntireRow method.
Here is an example:
Dim report as Worksheet
Set report = Excel.ActiveSheet
report.cells(1,1).EntireRow.Select
If you want to select the cells themselves, you can use the .UsedRange method.
Here is an example:
Dim report As Worksheet
Set report = Excel.ActiveSheet
report.Range(report.Cells(1, 1), report.Cells(1, report.UsedRange.Columns.Count)).Select
EDIT
Here is an example for part II of your question (as requested):
Sub test2()
Dim report As Worksheet
Set report = Excel.ActiveSheet
report.Cells(1, 1).EntireRow.Copy
report.Cells(report.UsedRange.Rows.Count + 1, 1).EntireRow.PasteSpecial xlPasteAll
End Sub
Be sure to note that the .UsedRange method also includes cells that have no values but have been formatted by the user; e.g., if you add bold font (even if you don't add the text itself) to a cell in row 1000, your .UsedRange.Rows.Count will be 1000.
Additionally, you can check my answer in the following link for more guidance. I've been told the notes are very helpful for beginners:
Excel Macro - Paste only non empty cells from one sheet to another (Stack Overflow)
You might want to look at this, and consider what you could do with Range.CurrentRegion, Range.Resize and Range.Offset, so you might get:
Range("A3").CurrentRegion.Copy
Additionally, there's no need to use Range.Select unless you want a user to see what is happening; instead of (for example) a Range.Select followed by a Selection.Copy() (which copies to the clipboard), you could just use a Range.Copy(Range), which copies direct to the target range.
As to the second part, you could:
Dim CopyRow as Long
CopyRow = Range("A3").CurrentRegion.Rows.Count
Range("A3").CurrentRegion.Copy(Range("A3").CurrentRegion.Offset(CopyRow))
Range("A3").Offset(CopyRow) = x ' Insert your reference to the Sheet 2 value here
I am aware that this thread is old, however I was looking for help with something similar. I knew my starting cell for my range, but the number of rows and columns were going to be dynamic. Using the following code worked for me:
Range("A2").Select
Range(Selection, Selection.End(xlDown).End(xlToRight)).Select
Hopefully anyone in the future can make use of this simple solution.