Loop to look for the closest value in a specific range - excel

I have to run the code twice to get the right answer.
The bug is somewhere in the for loop commented as "finds static.press cell location"
Sub find()
Dim A As Double
Dim B As Variant
Dim c As Integer
Dim x As Range
Dim cell As Range
Dim rng As Variant
Dim r As Variant
Dim Mx As Long
Dim i As Long
Dim target As Double
Set wks = Worksheets("comefri")
Set wkks = Worksheets("TEST")
Dim p As Long
'RPM INPUT
A = wkks.Range("C18").value
'Static Pressure Input
B = wkks.Range("C19").value
'copy comefri values to test sheet
Sheets("comefri").Range("A9:gs24").Copy Destination:=Sheets("test").Range("a1:gs16")
With test
' Row Numb used in rangelookup
c = Range("C20").value
d = Range(Cells(c, 102), Cells(c, 201))
For Each cell In [a2:gs16]
cell = WorksheetFunction.Round(cell, 1)
Next cell
'Finds RPM cell location
Set cell = Range("a:a").find(What:=A, LookAt:=xlWhole, MatchCase:=fasle, SearchFormat:=False)
Range("c20") = cell.row
'finds static.press cell location
target = B
Set rng = Range(Cells(c, 102), Cells(c, 201))
'rng.Offset(, 1).ClearContents
Mx = Application.Max(rng)
For Each B In rng
If Abs(target - B) < Mx Then
Mx = Abs(target - B)
i = B.row
p = B.Column
End If
Next B
Debug.Print i
Debug.Print p
Range("d19").value = p
Range("e19").value = i
End With
End Sub
The first time the code runs, I think it uses the values from previous inputs and the second time I run it, it uses the new inputs.
I think I need a line of code to clear old inputs.

The problem is that you pull the value of c from a cell value (Sheets("TEST").Range("C20")). You update the cell value (on this line: Range("c20") = cell.row), but don't update the value of c. As such, when you set your rng variable, it's still using the old c value.
To resolve this, instead of this:
Set rng = Range(Cells(c, 102), Cells(c, 201))
Use this:
Set rng = wkks.Range(wkks.Cells(cell.Row, 102), wkks.Cells(cell.Row,201))
Lastly some generic advice:
As Cyril already stated, use descriptive variable names instead of single letters
Once a variable is set in the code, use the variable instead of referencing worksheet cells
Use proper indenting for your code to make it easier to read and follow
Always fully qualify your range objects to avoid confusion
Use your worksheet objects that you set instead of referencing worksheets by their codename

Related

For each loop in VBA Excel

I am a beginner in VBA trying to loop through cells from a specified range that is entered into a refEdit on a user form, this range always has 2 columns but could have any number of rows. The first column is a category and the second column is numerical values. I want to find the sum of the corresponding values of a specific category. For example, very time I come across the word "coffee" in a cell I want to take the value in the cell to its right and start summing them to print the value of all coffee in cell C1. How can I get this to work?
Here is what I have been working with:
dim cell, myRange as Range
dim c as string
dim r as long
Set myRange = Range(RefEdit1.Text)
c = "coffee"
r = 0
For Each cell In myRange
If VBA.LCase(cell) = VBA.LCase(c) Then
r = r + ActiveCell.Offset(0, 1).Value
End If
next cell
range("C1") = r
SumIf vs Loop
Loops are usually best avoided due to slowing down the code.
SumIf 'is' not case-sensitive so you are also avoiding the 'LCase-business'.
When declaring variables in one line, you have to 'use an As' for each variable or it will be declared as Variant (cell).
Option Explicit
Sub testSumIf()
Dim myRange As Range
Dim c As String
Set myRange = Range(RefEdit1.Text)
c = "coffee"
Range("C1").Value _
= Application.SumIf(myRange.Columns(1), c, myRange.Columns(2))
End Sub
Sub testLoop()
Dim cell As Range, myRange As Range
Dim c As String
Dim r As Long
Set myRange = Range(RefEdit1.Text)
c = VBA.LCase("coffee")
For Each cell In myRange.Cells
If VBA.LCase(cell.Value) = c Then
r = r + cell.Offset(0, 1).Value
End If
Next cell
Range("C1").Value = r
End Sub

Excel - Loop through table out of bounds error

my code is to run through a table and store the cell color of column D while also storing the value of in column C as another variable. These variables are used to find a shape on another the "main" tab and update that color to the color that was stored in CellColor. When I added the loop part of the code I get an out of bounds error (-2147024809 (80070057)).
Sub Update()
Dim CellColor As Long
Dim ShapeColor As Variant
Dim rng As Range, Cell As Range
Dim i As Integer
Worksheets("Sheet1").Select
Set rng = Range("C2:C100")
For i = 2 To rng.Rows.Count
CellColor = rng.Cells(RowIndex:=i, ColumnIndex:="D").DisplayFormat.Interior.Color
ShapeColor = rng.Cells(RowIndex:=i, ColumnIndex:="C").Value
Worksheets("main").Shapes(ShapeColor).Fill.ForeColor.RGB = CellColor
i = i + 1
Next
Worksheets("main").Select
End Sub
Perhaps use a For Each loop here and Offset:
Set rng = Worksheets("Sheet1").Range("C2:C100")
Dim cell As Range
For Each cell In rng
ShapeColor = cell.Value
CellColor = cell.Offset(,1).DisplayFormat.Interior.Color
Worksheets("main").Shapes(ShapeColor).Fill.ForeColor.RGB = CellColor
Next
A brief explanation of your problem:
rng.Cells(RowIndex:=i, ColumnIndex:="C")
rng.Cells(RowIndex:=i, ColumnIndex:="D")
are not the cells you think they are, because they are offsetting but starting from column C. They are actually referring to columns E and F.
As an example: ? Range("C2").Cells(1, "C").Address returns $E$2, not $C$2.
Other points:
Remove the i = i + 1. Next is what increments i.
Avoid using Select: Set rng = Worksheets("Sheet1").Range("C2:C100").

Select range equal to variables in array using loop

I wrote a program using VBA which shown below. there was an array(ary) which contain(C,F,B,PC,PB). I create the loop to go through each variable in the array.
what I want to do with my code is I have a datasheet that includes that array values as categories. I want to assign each array values to p range. then execute data from the p range. then want to assign p to next array value and do the same.
but the problem is range p is firstly set ary(1)="C" and give the correct result. but after it becomes equal to "F" didn't work properly. it contains the same range previously gave. can anyone help me with this problem?
For i = 1 To UBound(ary)
cat = ary(i)
Set p = Nothing
Set c = Nothing
For Each c In Range("E:E")
If c.Value = cat Then
If p Is Nothing Then
Set p = c.Offset
Else
Set p = Union(p, c)
End If
End If
Next c
'get values
p.Offset(, -1).Copy Destination:=ws.Range("N" & Rows.Count).End(xlUp).Offset(1)
next i
The key error in your code is the idea that you might collect a range of non-consecutive cells and paste their value into a contiguous range. Excel can't do that. My code below collects qualifying values into an array and pastes that array into the target range.
The code below can't be exactly what you want because you didn't provide some vital information. However, please try it anyway with the aim of adapting it to your project.
Private Sub Review()
Dim Ws As Worksheet
Dim Rng As Range
Dim Rl As Long ' last row in column E
Dim Ary() As String
Dim Arr As Variant
Dim n As Long
Dim Cell As Range
Dim i As Long
Set Ws = Worksheets("Sheet1")
Ary = Split("C,F,B,PC,PB", ",") ' this array would be 0-based
Rl = Cells(Rows.Count, "E").End(xlUp).Row ' Range("E:E") has 1.4 million cells
Set Rng = Range(Cells(2, "E"), Cells(Rl, "E"))
For i = 0 To UBound(Ary)
ReDim Arr(1 To Rl)
n = 0
For Each Cell In Rng
If Cell.Value = Ary(i) Then
n = n + 1
Arr(n) = Cell.Offset(0, 1).Value
End If
Next Cell
If n Then
ReDim Preserve Arr(n)
'get values
Ws.Cells(Ws.Rows.Count, "N").End(xlUp).Offset(1) _
.Resize(UBound(Arr)).Value = Arr ' Application.Transpose(Arr)
End If
Next i
End Sub
This code works entirely on the ActiveSheet and then pastes the result to another sheet, named as "Sheet1". That isn't good practice. The better way would be to declare variables for both sheets and let the code refer to the variables so as to ensure that it has full control of which sheet it's working on at all times.
Set p = Union(p, c) will never be executed because it will only occur if p is NOT nothing, and Set p = Nothing is executed each time the outer loop iterates.

Search a Dynamic Number of rows in Column A for a specific string in VBA

I have a worksheet that contains a varying amount of Rows of data in Column A , within this worksheet I need to search for a specific string then copy the data contained in the Cell adjacent to it and paste into Column C, i.e if data was found in A2 then i need to copy the data from B2 and paste into C1. I can easily find and copy when the string appears once but the string will appear more than once 100% of time. here is when i run into issues.
The temporary code I have written for ease of understanding, searches the spreadsheet for the last Mention of A, get the row number, copy the B cell for that row number then pastes the value into C1.
I guess you need to use range variables for this but not 100% sure how to do it.
i have found no way to copy all mentions of A into a column, or ideally sum up the contents of the B cells. (I can do this, just long winded)
Ive placed my code below.
Sub ValueFinder()
Dim LastALocation As String
Dim ValueContent As String
LastALocation = Range("A:A").Find(What:="A", after:=Range("A1"), searchdirection:=xlPrevious).Row
ValueContent = Cells(LastALocation, 2)
Cells(1, 3) = ValueContent
End Sub
The spreadsheet that its using for more information, contains A,B,C on a loop in Column A and the odd numbers in Column B.
Thanks for any help your able to provide.
Mark
This will look for a string in Column A, and add to Column C the same row's B Column Value.
Sub find_move()
Dim foundCel As Range
Dim findStr As String, firstAddress As String
Dim i As Long
i = 1
findStr = "A"
Set foundCel = Range("A:A").Find(what:=findStr)
If Not foundCel Is Nothing Then
firstAddress = foundCel.Address
Do
Range("C" & i).Value = foundCel.Offset(0, 1).Value
Set foundCel = Range("A:A").FindNext(foundCel)
i = i + 1
Loop While Not foundCel Is Nothing And foundCel.Address <> firstAddress
End If
End Sub
Note: You should add the worksheet in front of all the range values, i.e. Sheets("Sheet1").Range("A:A").Find(...
Consider:
Sub LookingForA()
Dim s As String, rng As Range, WhichRows() As Long
Dim rFound As Range
ReDim WhichRows(1)
s = "A"
Set rng = Range("A:A")
Set rFound = rng.Find(What:=s, After:=rng(1))
WhichRows(1) = rFound.Row
Cells(1, 3) = Cells(rFound.Row, 2)
Do
Set rFound = rng.FindNext(After:=rFound)
If rFound.Row = WhichRows(1) Then Exit Do
ReDim Preserve WhichRows(UBound(WhichRows) + 1)
WhichRows(UBound(WhichRows)) = rFound.Row
Cells(Cells(Rows.Count, "C").End(xlUp).Row + 1, 3) = Cells(rFound.Row, 2)
Loop
End Sub
This code builds column C. It also builds an internal array of the row numbers in the event they are needed later.
EDIT#1:
To read about dynamic arrays:
Dynamic Arrays
or Google:
Excel VBA dynamic array

I can't get my VBA Excel Macro to stop at the end of the row

I have a row of data that changes once a month but it only changes roughly 30 cells out of 90 and every month they are different so I am trying to make a Macro to automate it.
The Macro looks at Cells A2 - B98 and searches for information that matches the Values of H2-I98 and if the values in A match H then it copies what the value is in I and replaces it in B but it doest stop at the end of the row i.e. at row 98 it loops infinatly. So I was hoping someone could find my error so that it wont loop for ever. Thanks
Sub Update_Holiday()
Dim Search As String
Dim Replacement As String
Dim rngTmp As Range
Dim rngSearch As Range
LastInputRow = Range("A65536").End(xlUp).Row
Set rngSearch = Worksheets("Holiday").Range(Cells(2, 1), Cells(98, 2))
For k = 2 to 98
Search = Worksheets("Holiday").Cells(k, 8)
Replacement = Worksheets("Holiday").Cells(k, 9)
With rngSearch
Set rngTmp = .Find(Search, LookIn:=xlValues)
If rngTmp Is Nothing Then
GoTo Go_to_next_input_row:
Else
Worksheets("Holiday").Cells(rngTmp.Row, rngTmp.Column + 1).Value = Replacement
End If
End With
Go_to_next_input_row:
Next K
End Sub
If I understand your question correctly: for each Cell in H2:H98, you're looking for a match in A2:A98. It won't necessarily be on the same row. If you find a match in Column A, you want to take the value from Column B and put it in Column I on the same row as the search value we just looked for. In this case, this code will work:
Option Explicit
Sub Test()
Dim ws As Worksheet
Dim srcRng As Range '' Source range
Dim schRng As Range '' Search range
Dim c As Range
Dim search As Range
Set ws = ThisWorkbook.Sheets(1)
Set srcRng = ws.Range("H2:H98")
Set schRng = ws.Range("A2:A98")
For Each c In srcRng '' Iterate through your source range
Set search = schRng.Find(c.Value, LookIn:=xlValues, SearchDirection:=xlNext) '' Find the value from column H in column A
If Not search Is Nothing Then
c.Offset(, 1).Copy search.Offset(, 1) '' Get the value from column B, from the same row as the value it found in column A
'' Then paste that value in column I, on the same row as the value we searched for from column H
End If
Next c
GoTo statements are generally (generally, not always) very, very bad practice. Especially in this kind of situation. You don't need them, it just makes your code convoluted.

Resources