Creating a vba loop that grabs cell values - excel

I'm trying to create a macro for vba that grabs values entered in my A column of cells 1-1000, and then takes those values and plugs them into an function.
Rather than define a 1000 different values as:
x1 = Worksheets("Sheet1").Range("A1").Value
x2 = Worksheets("Sheet1").Range("A2").Value
x3 = Worksheets("Sheet1").Range("A3").Value
... etc
and then plugging them into my function
Dim dy As Integer, fx As Integer
dy = Range("B2").Value - Range("B1").Value
fx= dy*(x1+x2+x3....)
is there someway I can create a do loop that runs from cell A1 to A1000 grabbing each of their own values and plugging it into my function? Here's what I have so far but I'm not sure how I would have it grab the values entered in the cells.
xi = 1
Do
xi = 1 + xi
If xi = 1000 Then Exit Do
Count = Count + 1
Loop

'create a zero-based array o9f the values in A1:A1000
dim x as variant
with Worksheets("Sheet1")
x = application.transpose(.range("A1:A1000").value)
end with
'sum all of x
dim i as long, sumX as double
for i = lbound(x) to ubound(x)
sumX = sumX + x(i)
next i
'another way to sum A1:A1000
with Worksheets("Sheet1")
sumX = application.sum(.range("A1:A1000").value)
end with
'your function
Dim dy As long, fx As long
with Worksheets("Sheet1")
dy = .Range("B2").Value - .Range("B1").Value
end with
fx = dy * sumX

Below Query Works for you. The code flexible to get the row count in column "A". No need to hard code the upper bound value
Dim dy As Integer, fx As Integer, iCellSum As Integer
Sub Main()
iRowCount = Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
iCellSum = 0
For i = 1 To iRowCount
iCellSum = iCellSum + Sheets("Sheet1").Cells(i, 1)
Next
dy = Range("B2").Value - Range("B1").Value
fx = dy * iCellSum
End Sub

Related

Increase Chart Data Series By Two Rows with VBA

I am working on a chart that I want to change data series every few seconds. After ten seconds, I want the data series to move from SERIES(Input!$A$4:$D$4,Input!$E$3:$F$3,Input!$E$4:$F$4,1) to SERIES(Input!$A$6:$D$6,Input!$E$3:$F$3,Input!$E$6:$F$6,1).
I have tried adapting the below code, but so far am only able to add a series, and not the data series row.
Sub ChangeChartRange()
Dim i As Integer, r As Integer, n As Integer, p1 As Integer, p2 As Integer, p3 As Integer
Dim rng As Range
Dim ax As Range
'Cycles through each series
Sheets("Dashboard").ChartObjects("Chart 1").Activate
'For n = 1 To ActiveChart.SeriesCollection.Count Step 1
r = 0
'Finds the current range of the series and the axis
For i = 1 To Len(ActiveChart.SeriesCollection(1).Formula) Step 1
If Mid(ActiveChart.SeriesCollection(1).Formula, i, 1) = "," Then
r = r + 1
If r = 1 Then p1 = i + 1
If r = 2 Then p2 = i
If r = 3 Then p3 = i
End If
Next i
MsgBox ActiveChart.SeriesCollection(1).Formula
'Defines new range
Set rng = Range(Mid(ActiveChart.SeriesCollection(1).Formula, p2 + 1, p3 - p2 - 1))
Set rng = Range(rng, rng.Offset(0, 1))
'Sets new range for each series
ActiveChart.SeriesCollection(1).Values = rng
'Updates axis
'Set ax = Range(Mid(ActiveChart.SeriesCollection(1).Formula, p1, p2 - p1))
'Set ax = Range(ax, ax.Offset(0,1))
'ActiveChart.SeriesCollection(1).XValues = ax
End Sub

How to identify table data using merged cells?

I am trying to interpolate a value in the table. However since my column cells are merged together, my code won't read the values. So far whenever i unmerge those columns, it works completely fine and gives me the value i want. How do i integrate merged cells as a matrices?
Sub brent()
Dim i As Integer, j As Integer
Dim P As Single, P1 As Single, P2 As Single
Dim M As Single, M1 As Single, M2 As Single
Dim inputmat()
nrow = 29
ncol = 2
P = Range("Axial").Value
ReDim inputmat(nrow, ncol)
For i = 1 To nrow
For j = 1 To ncol
inputmat(i, j) = Cells(5 + i, 6 + j)
Next j
Next i
If (P > inputmat(1, 1)) Or (P < inputmat(nrow, 1)) Then Range("PM").Value =
"NG"
Else
For i = 1 To nrow - 1
If (P <= inputmat(i, 1)) And (P >= inputmat(i + 1, 1)) Then
P1 = inputmat(i, 1)
P2 = inputmat(i + 1, 1)
M1 = inputmat(i, 2)
M2 = inputmat(i + 1, 2)
End If
Next i
For i = 1 To nrow
M = M1 + (P - P1) * (M2 - M1) / (P2 - P1)
Next i
Range("PM").Value = M
End If
End Sub
I know that there is problem under the "input (i,j)= cells(5+i,6+j)"
Is there any way to read that black column between the merged cells?
Sub FindMergedCells()
Dim tbl As Range, cll As Range
Dim i As Integer
i = 1
Set tbl = Range("A1:E4")
For Each cll In tbl
If cll.MergeCells Then
Cells(i, 7) = "Cell " & cll.Address & " is merged"
i = i + 1
End If
Next
End Sub

Can't make Loop on Excel VBA and print results

I am new to Excel VBA and I want to calculate the distance between two atoms and make a loop to calculate it for all wanted cases
with coordinate B(i), C(i), D(i) in the Excel sheet correspond to x,y,z cartesian coordinate..
these atoms are located : One in a row (i) and the other in a row (i+5)
I write this algorithm but I cant transfer it to excel VBA
For i=4 to 1000
For j=9 to 1000
d=SQRT(POWER(B(i)-B(j),2)+ POWER(C(i)-C(j),2)+ POWER(D(i)-D(j),2))
print **d** in (P(i)) #want to print the distance **d** in a case
j=j+4 # **j** is a multiple of 4
i=i+4 # **i** is a multiple of 4
next i
Thanks, this is my first question
I think that the following should work for you:
Sub FindDistances()
Dim i As Long, j As Long
Dim r As Long, c As Long 'row and column indices for output
Dim data As Variant
Application.ScreenUpdating = False 'useful when doing a lot of writing
data = Range("B4:D1000").Value 'data is a 1-based array
c = 5 'column E
For i = 1 To UBound(data) - 5 Step 4
r = 1 'first row printed in -- adjust if need be
For j = i + 5 To UBound(data) Step 4
Cells(r, c).Value = Sqr((data(i, 1) - data(j, 1)) ^ 2 + (data(i, 2) - data(j, 2)) ^ 2 + (data(i, 3) - data(j, 3)) ^ 2)
r = r + 1
Next j
c = c + 1
Next i
Application.ScreenUpdating = True
End Sub
Something like this? In VBA, you refer to cells like Cells(row, column). Data is supposed to be located in a worksheet named Sheet1. I'm calculating each dimension separately (d1, d2, d3) just for reading simplicity. You can merge those four lines in one if you like. EDIT: reading your comments above, I add a nested loop (j).
Sub Distances()
Dim i As Integer
Dim j As Integer
Dim d1 As Double, d2 As Double, d3 As Double, d As Double
For i = 4 To 1000 Step 4 'Can't understand your data, but Step 4 tries to account for your j=j+4 and i=i+4
For j = 9 To 1000 Step 4
d1 = (Worksheets("Sheet1").Cells(i, 2) - Worksheets("Sheet1").Cells(j, 2)) ^ 2
d2 = (Worksheets("Sheet1").Cells(i, 3) - Worksheets("Sheet1").Cells(j, 3)) ^ 2
d3 = (Worksheets("Sheet1").Cells(i, 4) - Worksheets("Sheet1").Cells(j, 4)) ^ 2
d = Sqr(d1 + d2 + d3)
Worksheets("Sheet1").Cells(i, 16).Value = d
Next j
Next i
End Sub
Option Explicit
Sub AtomDistance()
'
' AtomDistance Macro1
'
'
Dim i As Integer
Dim j As Integer
Dim Distance As Double
Dim Column As String
Column = InputBox("Which column you want to print results(put a letter)?")
Dim MyCell11 As String
Dim MyCell12 As String
Dim MyCell13 As String
Dim MyCell21 As String
Dim MyCell22 As String
Dim MyCell23 As String
Dim MyCell3 As String
j = 9
For i = 4 To 12
MyCell3 = Column & i
MyCell11 = "B" & i
MyCell12 = "C" & i
MyCell13 = "D" & i
MyCell21 = "B" & j
MyCell22 = "C" & j
MyCell23 = "D" & j
Distance = (((Range(MyCell11).Value - Range(MyCell21).Value) ^ 2) + ((Range(MyCell12).Value - Range(MyCell22).Value) ^ 2) + ((Range(MyCell13).Value - Range(MyCell23).Value) ^ 2)) ^ 0.5
If i Mod 4 = 0 Or j Mod 4 = 0 Then
Range(MyCell3).Value = Distance
End If
j = j + 1
Next i

Filtering in VBA after finding combinations

After some help on this website I am now looking for more. This was my previous post: stacking and layering boxes in excel
I am now able to make all possible combinations. However my next step would be to set some parameters. By this I mean the height and weight of the boxes. If I were to place on "Sheet2" in Column A by box names (A,B,....) Column B by weight (kg) and Column C by height (millimeters). Then on "Sheet3" I place my maximum height and maximum weight. B2 maximum weight of 30 kg and C3 maximum height of 500 mm.
How can I get my macro to check against these parameters and if they do fit them they are placed in the column as in my previous question and if it goes over my weight or height it does not bother with placing it.
Hope to hear soon :) Starting to enjoy excel!
Edit:
Box name Weight height
A 1 0.12
B 5 0.92
C 3 0.5
D 2 0.34
........etc
This is how I would place my input information. I would like this for many boxes, maybe even up to 100
as a enhancement to the previous solution
input format
(Please implement your own input/output farmat after studying my code)
<num of box> <box name 1> <box name 2> ... <box name N>
<max height> <height 1> <height 2>...
<max weight> <weight 1> <weight 2> ...
<output result 1>
<output result 2>
.
.
.
sample Input & output
3 A B C D E
7.7 3 1 1 1 2
5.5 2 1 2 3 3
A
B
AB
C
AC
BC
ABC
D
AD
BD
CD
E
AE
BE
CE
Not limited to integer, you can use floating numbers
Code:
Function stackBox()
Dim ws As Worksheet
Dim width As Long
Dim height As Long
Dim numOfBox As Long
Dim optionsA() As Variant
Dim results() As Variant
Dim str As String
Dim outputArray As Variant
Dim i As Long, j As Long
Dim currentSymbol As String
'------------------------------------new part----------------------------------------------
Dim maxHeight As Double
Dim maxWeight As Double
Dim heightarray As Variant
Dim weightarray As Variant
Dim totalHeight As Double
Dim totalWeight As Double
'------------------------------------new part----------------------------------------------
Set ws = Worksheets("Sheet1")
With ws
'clear last time's output
height = .Cells(.Rows.Count, 1).End(xlUp).row
If height > 3 Then
.Range(.Cells(4, 1), .Cells(height, 1)).ClearContents
End If
numOfBox = .Cells(1, 1).Value
width = .Cells(1, .Columns.Count).End(xlToLeft).Column
If width < 2 Then
MsgBox "Error: There's no item, please fill your item in Cell B1,C1,..."
Exit Function
End If
'------------------------------------new part----------------------------------------------
maxHeight = .Cells(2, 1).Value
maxWeight = .Cells(3, 1).Value
ReDim heightarray(1 To 1, 1 To width - 1)
ReDim weightarray(1 To 1, 1 To width - 1)
heightarray = .Range(.Cells(2, 2), .Cells(2, width)).Value
weightarray = .Range(.Cells(3, 2), .Cells(3, width)).Value
'------------------------------------new part----------------------------------------------
ReDim optionsA(0 To width - 2)
For i = 0 To width - 2
optionsA(i) = .Cells(1, i + 2).Value
Next i
GenerateCombinations optionsA, results, numOfBox
' copy the result to sheet only once
ReDim outputArray(1 To UBound(results, 1) - LBound(results, 1) + 1, 1 To 1)
Count = 0
For i = LBound(results, 1) To UBound(results, 1)
If Not IsEmpty(results(i)) Then
'rowNum = rowNum + 1
str = ""
totalHeight = 0#
totalWeight = 0#
For j = LBound(results(i), 1) To UBound(results(i), 1)
currentSymbol = results(i)(j)
str = str & currentSymbol 'results(i)(j) is the SYMBOL e.g. A, B, C
'look up box's height and weight , increment the totalHeight/totalWeight
updateParam currentSymbol, optionsA, heightarray, weightarray, totalHeight, totalWeight
Next j
If totalHeight < maxHeight And totalWeight < maxWeight Then
Count = Count + 1
outputArray(Count, 1) = str
End If
'.Cells(rowNum, 1).Value = str
End If
Next i
.Range(.Cells(4, 1), .Cells(UBound(outputArray, 1) + 3, 1)).Value = outputArray
End With
End Function
Sub updateParam(ByRef targetSymbol As String, ByRef symbolArray As Variant, ByRef heightarray As Variant, ByRef weightarray As Variant, ByRef totalHeight As Double, ByRef totalWeight As Double)
Dim i As Long
Dim index As Long
index = -1
For i = LBound(symbolArray, 1) To UBound(symbolArray, 1)
If targetSymbol = symbolArray(i) Then
index = i
Exit For
End If
Next i
If index <> -1 Then
totalHeight = totalHeight + heightarray(1, index + 1)
totalWeight = totalWeight + weightarray(1, index + 1)
End If
End Sub
Sub GenerateCombinations(ByRef AllFields() As Variant, _
ByRef Result() As Variant, ByVal numOfBox As Long)
Dim InxResultCrnt As Integer
Dim InxField As Integer
Dim InxResult As Integer
Dim i As Integer
Dim NumFields As Integer
Dim Powers() As Integer
Dim ResultCrnt() As String
NumFields = UBound(AllFields) - LBound(AllFields) + 1
ReDim Result(0 To 2 ^ NumFields - 2) ' one entry per combination
ReDim Powers(0 To NumFields - 1) ' one entry per field name
' Generate powers used for extracting bits from InxResult
For InxField = 0 To NumFields - 1
Powers(InxField) = 2 ^ InxField
Next
For InxResult = 0 To 2 ^ NumFields - 2
' Size ResultCrnt to the max number of fields per combination
' Build this loop's combination in ResultCrnt
ReDim ResultCrnt(0 To NumFields - 1)
InxResultCrnt = -1
For InxField = 0 To NumFields - 1
If ((InxResult + 1) And Powers(InxField)) <> 0 Then
' This field required in this combination
InxResultCrnt = InxResultCrnt + 1
ResultCrnt(InxResultCrnt) = AllFields(InxField)
End If
Next
If InxResultCrnt = 0 Then
Debug.Print "testing"
End If
'additional logic here
If InxResultCrnt >= numOfBox Then
Result(InxResult) = Empty
Else
' Discard unused trailing entries
ReDim Preserve ResultCrnt(0 To InxResultCrnt)
' Store this loop's combination in return array
Result(InxResult) = ResultCrnt
End If
Next
End Sub

circular reference excel formula makes VBA method return 0

I writing a VBA plug in function to perform rectangular rounding of a series. In my VBA method I'd like to detect if there are empty cells above the cell containing the formula/VBA method. But, if I use ActiveCell in my method Excel complains of circular references and returns 0 instead of the return value of my method. Example method:
Function MovingAverageSmooth(r As Range, m As Integer)
' returns a smoothed average using the 'rectangular' method
Dim cStart As Long, x As Long, total As Double, activeColumn As Long
Dim vc As Long, vr As Long, count As Double, beforeCount As Long, afterCount As Long
vc = r.Column
vr = r.Row
rStart = Max(1, vr - m)
currentValue = Cells(vr, vc).Value
activeColumn = ActiveCell.Column
For x = rStart To vr + m
If Application.IsNumber(Cells(x, vc).Value) Then
total = total + Cells(x, vc).Value
count = count + 1
If Application.IsNumber(Cells(x, activeColumn).Value) Then
If x < vr Then
beforeCount = beforeCount + 1
End If
If x > vr Then
afterCount = afterCount + 1
End If
End If
End If
Next
MovingAverageSmooth = total / count
If afterCount = 0 Or beforeCount = 0 Or count = 0 Then
MovingAverageSmooth = currentValue
End If
End Function
I think this will work for you. As mentioned in my comment, Application.Caller returns the cell that called the function:
Function MovingAverageSmooth(r As Range, m As Integer)
' returns a smoothed average using the 'rectangular' method
Dim cStart As Long, x As Long, total As Double, activeColumn As Long
Dim vc As Long, vr As Long, count As Double, beforeCount As Long, afterCount As Long
vc = r.Column
vr = r.Row
rStart = Max(1, vr - m)
currentValue = Cells(vr, vc).Value
activeColumn = Application.Caller.Column
For x = rStart To vr + m
If Application.IsNumber(Cells(x, vc).Value) Then
total = total + Cells(x, vc).Value
count = count + 1
If Application.IsNumber(Cells(x, activeColumn).Value) Then
If x < vr Then
beforeCount = beforeCount + 1
End If
If x > vr Then
afterCount = afterCount + 1
End If
End If
End If
Next
MovingAverageSmooth = total / count
If afterCount = 0 Or beforeCount = 0 Or count = 0 Then
MovingAverageSmooth = currentValue
End If
End Function

Resources