Sub GetMaxl()
Dim nMonths As Integer, nRegions As Integer
Dim iRow As Integer, iCol As Integer
Dim regionMax As Double, monthMax As Double
Dim maxScore As Integer
With wsSales.Range("A3")
nMonths = Range(.Offset(0, 1), .Offset(0, 1).End(xlToRight)) _
.Columns.Count
nRegions = Range(.Offset(1, 0), .Offset(1, 0).End(xlDown)) _
.Rows.Count
.Offset(0, nMonths + 1) = "MaxScore"
.Offset(nRegions + 1, 0) = "MaxScore"
For iRow = 1 To nRegions
regionMax = 0
For iCol = 1 To nMonths
regionMax = WorksheetFunction.Max(Range(.Offset(iRow, iCol), .End(xlToRight)))
Debug.Print , regionMax
Next iCol
.Offset(iRow, nMonths + 1) = regionMax
Next iRow
For iCol = 1 To nMonths
monthMax = 0
For iRow = 1 To nRegions
monthMax = WorksheetFunction.Max(Range(.Offset(iRow, iCol), .End(xlDown)))
Next iRow
.Offset(nRegions + 1, iCol) = monthMax
Next iCol
End With
End Sub
I am trying to get the max score against columns and rows in a loop but I am not getting correct results.
It can be done easier and faster
Option Explicit
Sub GetMaxl()
Dim Rng As Range, rng_total_right As Range, rng_total_down As Range
Set Rng = wsSales.Range("A3").CurrentRegion
'get the ranges for max column and row at right and down
Set rng_total_right = Intersect(Rng.Offset(, 1), wsSales.Columns(Rng.Column + Rng.Columns.Count))
Set rng_total_down = Intersect(Rng.Offset(1, 0), wsSales.Rows(Rng.Row + Rng.Rows.Count))
With rng_total_right ' max column
.NumberFormat = "0"
.FormulaR1C1 = "=MAX(RC[-" & Rng.Columns.Count - 1 & "]:RC[-1])" ' insert formulas and calculate them
.Value = .Value 'replace formulas by values
.Cells(1) = "MaxScore" 'make header
End With
With rng_total_down 'max row
.NumberFormat = "0"
.FormulaR1C1 = "=MAX(R[-" & Rng.Rows.Count - 1 & "]C:R[-1]C)"
.Value = .Value
.Cells(1) = "MaxScore"
End With
End Sub
Related
I have a data like this :
A049
A050
A051
A053
A054
A055
A056
A062
A064
A065
A066
And I want the output like :
As you can see, I want the ranges which are in consecutive order
I am trying some thing like this:
Private Sub CommandButton1_Click()
Set wb = ThisWorkbook
lastRow = wb.Sheets("Sheet1").Range("A" & wb.Sheets("Sheet1").Rows.Count).End(xlUp).Row
For i = 2 To lastRow
r = wb.Sheets("Sheet1").Range("A" & i).Value
If wb.Sheets("Sheet1").Range("A" & i).Value = wb.Sheets("Sheet1").Range("A" & i+1).Value
Next i
End Sub
But not helping me
Am feeling charitable so have tried some code which should work. It assumes your starting values are in A1 down and puts results in C1 down.
Sub x()
Dim v1, v2(), i As Long, j As Long
v1 = Range("A1", Range("A" & Rows.Count).End(xlUp)).Value
ReDim v2(1 To UBound(v1, 1), 1 To 2)
For i = LBound(v1, 1) To UBound(v1, 1)
j = j + 1
v2(j, 1) = v1(i, 1)
If i <> UBound(v1, 1) Then
Do While Val(Right(v1(i + 1, 1), 3)) = Val(Right(v1(i, 1), 3)) + 1
i = i + 1
If i = UBound(v1, 1) Then
v2(j, 2) = v1(i, 1)
Exit Do
End If
Loop
End If
If v1(i, 1) <> v2(j, 1) Then v2(j, 2) = v1(i, 1)
Next i
Range("C1").Resize(j, 2) = v2
End Sub
Try the below code
Private Sub CommandButton1_Click()
Set wb = ThisWorkbook
lastRow = wb.Sheets("Sheet1").Range("A" & wb.Sheets("Sheet1").Rows.Count).End(xlUp).Row
Dim lastNum, Binsert As Integer
Dim firstCell, lastCell, currentCell As String
Binsert = 1
lastNum = getNum(wb.Sheets("Sheet1").Range("A1").Value)
firstCell = wb.Sheets("Sheet1").Range("A1").Value
For i = 2 To lastRow
activeNum = getNum(wb.Sheets("Sheet1").Range("A" & i).Value)
currentCell = wb.Sheets("Sheet1").Range("A" & i).Value
If (activeNum - lastNum) = 1 Then
'nothing
Else
lastCell = wb.Sheets("Sheet1").Range("A" & (i - 1)).Value
wb.Sheets("Sheet1").Range("B" & Binsert).FormulaR1C1() = firstCell
If (firstCell <> lastCell) Then
wb.Sheets("Sheet1").Range("C" & Binsert).FormulaR1C1() = lastCell
End If
Binsert = Binsert + 1
firstCell = wb.Sheets("Sheet1").Range("A" & i).Value
End If
lastNum = activeNum
Next i
'last entry
wb.Sheets("Sheet1").Range("B" & Binsert).FormulaR1C1() = firstCell
If (firstCell <> currentCell) Then
wb.Sheets("Sheet1").Range("C" & Binsert).FormulaR1C1() = currentCell
End If
End Sub
Public Function getNum(ByVal num As String) As Integer
getNum = Val(Mid(num, 2))
End Function
Another solution. It loops backwards from last row to first row.
Option Explicit
Public Sub FindConsecutiveValues()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim lRow As Long 'find last row
lRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
Dim lVal As String 'remember last value (stop value)
lVal = ws.Range("A" & lRow).Value
Const fRow As Long = 2 'define first data row
Dim i As Long
For i = lRow To fRow Step -1 'loop from last row to first row backwards
Dim iVal As Long
iVal = Val(Right(ws.Range("A" & i).Value, Len(ws.Range("A" & i).Value) - 1)) 'get value of row i without A so we can calculate
Dim bVal As Long
bVal = 0 'reset value
If i <> fRow Then 'if we are on the first row there is no value before
bVal = Val(Right(ws.Range("A" & i - 1).Value, Len(ws.Range("A" & i - 1).Value) - 1)) 'get value of row i-1 without A
End If
If iVal - 1 = bVal Then
ws.Rows(i).Delete 'delete current row
Else
If lVal <> ws.Range("A" & i).Value Then 'if start and stop value are not the same …
ws.Range("B" & i).Value = lVal 'write stop value in column B
End If
lVal = ws.Range("A" & i - 1).Value 'remember now stop value
End If
Next i
End Sub
I want to check if the text value in a cell is the same as in the cell below with a for loop.
If the value in Cell(1) and Cell(2) does not match I want the value from Cell(3) written in Cell(4).
I get an error
"Overflow (Error 6)"
Dim i As Integer
For i = 1 To Rows.Count
If Cells(2 + i,21) = Cells(3 + i,21) Then
i = i + 1
Else
a = Cells(3 + i, 1)
j = j + 1
Cells(228 + j, 3) = a
End If
Next i
End Sub
I have a production output and a timeline from 6 am to 12 am and I want to create a timetable as seen below.
Screenshot:
You could use
Option Explicit
Sub test()
Dim LastRowA As Long, i As Long, j As Long, LastRowW As Long
Dim StartTime As Date, EndTime As Date, strOutPut
j = 0
With ThisWorkbook.Worksheets("Sheet1")
LastRowA = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 3 To LastRowA
If i > j - 1 Then
StartTime = .Range("A" & i).Value
strOutPut = .Range("U" & i).Value
For j = i + 1 To LastRowA + 1
If strOutPut <> .Range("U" & j).Value Then
EndTime = .Range("A" & j - 1).Value
LastRow = .Cells(.Rows.Count, "W").End(xlUp).Row
.Range("W" & LastRow + 1).Value = StartTime
.Range("X" & LastRow + 1).Value = EndTime
.Range("Y" & LastRow + 1).Value = strOutPut
Exit For
End If
Next j
End If
Next i
End With
End Sub
Result
Here I'm using a dictionary which will store every time for every product comma separated, so later will split that and take the first and last occurrence:
Sub TimeTable()
'Declare an array variable to store the data
'change MySheet for your sheet name
arr = ThisWorkbook.Sheets("MySheet").UsedRange.Value 'this will store the whole worksheet, the used area.
'Declare a dictionary object
Dim Products As Object: Set Products = CreateObject("Scripting.Dictionary")
'Loop through the array
Dim i As Long
For i = 3 To UBound(arr) 'start from row 3 because of your screenshoot
If arr(i, 21) = vbNullString Then GoTo NextRow 'if column U is empty won't add anything
If Not Products.Exists(arr(i, 21)) Then '21 is the column index for column U
Products.Add arr(i, 21), arr(i, 1)
Else
Products(arr(i, 21)) = arr(i, 21) & "," & arr(i, 1)
End If
NextRow:
Next i
Erase arr
'Redim the array to fit your final data, 4 columns and as many rows as products
ReDim arr(1 To Products.Count + 1, 1 To 4)
'Insert the headers
arr(1, 1) = "Time"
arr(1, 4) = "Product / Error"
'Now loop through the dictionary
Dim Key As Variant, MySplit As Variant
i = 2
For Each Key In Products.Keys
MySplit = Split(Products(Key), ",")
arr(i, 1) = MySplit(LBound(MySplit))
arr(i, 2) = "-"
arr(i, 3) = MySplit(UBound(MySplit))
arr(i, 4) = Key
i = i + 1
Next Key
'I don't know where are you going to paste your data, so I'm making a new worksheet at the end of your workbook
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
With ws
.Range("A1").Resize(UBound(arr), UBound(arr, 2)).Value = arr
.Range("A1:C1").Merge
End With
End Sub
I tried to make macro for my daily job, but i cannot use IF as formula due to so many item in my excel file, so solution is to convert formula to VBA code.
I need help to convert if formula to VBA code in excel as below:
=IF(J2<>J1,AD2-X2,AE1-X2).
Here is an answer to your question. However, it is limited to only work with OP information. Also, if the calculations are taking too long then, you should try setting your calculation to Manual (Formulas->Calculation Options->Manual).
Option Explicit
Public Sub RunIF()
Dim vntOut As Variant
Dim rngSame As Range
With ActiveSheet
Set rngSave = .Range("X2")
If (LCase(Trim(.Range("J2").Value)) <> LCase(Trim(.Range("J1").Value))) Then
vntOut = .Range("AD2").Value - rngSave.Value
Else
vntOut = .Range("AE1").Value - rngSave.Value
End If
.Range("AE2").value = vntOut
Set rngSave = Nothing
End With
End Sub
And here is your code converted to use Column J:
Private Sub CommandButton12_Click()
Dim x As Long
Dim LastRow As Long
Dim i as long
With Sheets("Shipping Schedule")
LastRow = .Cells(.Rows.Count, "J").End(xlUp).Row
For i = 2 to LastRow
set r = .Range("J" & I)
'For Each r In .Range("J2:J" & LastRow)
If LCase(Trim(r.Value)) <> LCase(Trim(r.Offset(-1, 0).Value)) Then
'ae2 = "AD2" - "x2"
r.Offset(0, 21).Value = r.Offset(0, 20).Value - r.Offset(0, 14).Value
Else
'ae2 = "AE1" - "x2"
r.Offset(0, 21).Value = r.Offset(-1, 21).Value - r.Offset(0, 14).Value
End If
set r = nothing
Next i
End With
End Sub
However, you should increment with I instead of for each as the cells are dependent on the previous row and excel may not loop through the range like you would prefer.
Excel Formula to VBA: Fill Column
Sub FillColumn()
Const cCol As Variant = "J" ' Last-Row-Column Letter/Number
Const cCol1 As Variant = "AD"
Const cCol2 As Variant = "X"
Const cCol3 As Variant = "AE"
Const cFirstR As Long = 1 ' First Row
Dim rng As Range ' Last Used Cell in Last-Row-Column
Dim i As Long ' Row Counter
Set rng = Columns(cCol).Find("*", , xlFormulas, , xlByColumns, xlPrevious)
If rng Is Nothing Then Exit Sub
For i = cFirstR To rng.Row - 1
If Cells(i + 1, cCol) <> Cells(i, cCol) Then
Cells(i + 1, cCol3) = Cells(i + 1, cCol1) - Cells(i + 1, cCol2)
Else
Cells(i + 1, cCol3) = Cells(i, cCol3) - Cells(i + 1, cCol2)
End If
Next
End Sub
Private Sub CommandButton12_Click()
Dim x As Long
Dim LastRow As Long
Sheets("Shipping Schedule").Select
With Sheets("Shipping Schedule")
LastRow = .Cells(.Rows.Count, "N").End(xlUp).Row
For Each r In .Range("N2:N" & LastRow)
If r.Value <> "" Then
r.Offset(0, 19).Value = ………………………………….
End if
Next r
End With
End Sub
I am creating a summary macro and I need to add up all the values of column C and D into the merged cell in E. In the image attached the sums are already placed to show the result I want. I already have code to merge the cells in column E based on the names in A. IE Sum up all overdue and critical for bob and place in merged column, then nick. Here is what I have I just need help getting the sum:
Sub MergeSameCell()
Dim Rng As Range, xCell As Range
Dim xRows As Integer
Set WorkRng = ThisWorkbook.Worksheets("Summary").Range("A:A")
lastRow = ActiveSheet.Columns("A").Cells.Find("*", SearchOrder:=xlByRows,
LookIn:=xlValues, SearchDirection:=xlPrevious).Row
xRows = lastRow
For Each Rng In WorkRng.Columns
For i = 1 To xRows - 1
For j = i + 1 To xRows
If Rng.Cells(i, 1).Value <> Rng.Cells(j, 1).Value Then
Exit For
End If
Next
WorkRng.Parent.Range(Rng.Cells(i, 5), Rng.Cells(j - 1, 5)).Merge
i = j - 1
Next
Next
End Sub
The below uses your enclosed data specifically and assumes the data has already been sorted by column A and the cells in column E are already merged.
Public Sub GroupSum()
Dim i0 As Long, i1 As Long, strName As String
With ActiveSheet
For i0 = 2 To .UsedRange.Rows.Count
If Not .Cells(i0, 1).Value = strName Then
strName = .Cells(i0, 1)
i1 = i0
End If
.Cells(i1, 5).Value = .Cells(i0, 3).Value + .Cells(i0, 4).Value + .Cells(i1, 5).Value
Next i0
End With
End Sub
I will leave the alignment formatting of the merged cells to you.
Option Explicit
Sub MergeSameCell()
Dim clientRng As Range
Dim lastRow As Long, lastClientRow As Long
With ThisWorkbook.Worksheets("Summary")
.Columns(5).UnMerge
Set clientRng = .Range("A2")
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Do
lastClientRow = .Columns(1).Find(what:=clientRng.Value, after:=clientRng, _
lookat:=xlWhole, SearchDirection:=xlPrevious).Row
With clientRng.Offset(0, 4)
.Resize(lastClientRow - clientRng.Row + 1, 1).Merge
.Formula = "=sumifs(c:c, a:a, " & Chr(34) & clientRng.Value2 & Chr(34) & ")+" & _
"sumifs(d:d, a:a, " & Chr(34) & clientRng.Value2 & Chr(34) & ")"
'optionally revert the formulas to their returned value
'value = .value2
End With
Set clientRng = clientRng.Offset(lastClientRow - clientRng.Row + 1, 0)
Loop While clientRng.Row <= lastRow
End With
End Sub
This removes a couple of loops:
Sub MergeSameCell()
With ThisWorkbook.Worksheets("Summary")
Dim i as Long
For i = 2 To .Rows.Count
If .Cells(i, 1) = "" Then Exit Sub
Dim x As Long
x = .Evaluate("MATCH(TRUE," & .Cells(i, 1).Address & "<>" & .Range(.Cells(i, 1), .Cells(.Rows.Count, 1)).Address & ",0) - 2 + " & i)
.Cells(i, 5).Value = Application.Sum(.Range(.Cells(i, 3), .Cells(x, 4)))
.Range(.Cells(i, 5), .Cells(x, 5)).Merge
i = x
Next i
End With
End Sub
I am trying to create a code in Excel VBA, to locate the beginning (Cell Address) and the end (Cell Address) of coloured rows in a table. The table is a timeline(Horizontal axis- Dates, Vertical axis - General Text). The coloured rows all do not start in the first column, but start in different columns.
Any help?
How's this?
Sub findColoredRows()
Dim startCol As Integer, endCol As Integer, o As Integer
Dim ws As Worksheet
Dim i As Integer, k As Integer
Dim startRow As Long, endRow As Long
Dim cellColor As String, noColor As String
Dim cel As Range
noColor = -4142 ' this is the color index of NO coloring
k = 3
Set ws = ActiveSheet
With ws
startRow = .Cells(1, 3).End(xlDown).Row
startCol = .Cells(1, 3).Column
Do While startRow > 100 ' I assume your table starts before row 100. So, if there's no data before row 100, check next column
k = k + 1
startRow = .Cells(1, k).End(xlDown).Row
startCol = k
Loop
'Now, we have our starting row - get end row.
endRow = .Cells(startRow, k).End(xlDown).Row
endCol = .Cells(startRow, startCol).End(xlToRight).Column
Debug.Print "Start row: " & startRow & ", start column: " & startCol
' How many non colored cells is there in our range?
Dim noColorCells As Integer
For Each cel In .Range(.Cells(startRow, startCol), .Cells(endRow, endCol))
If cel.Interior.ColorIndex = noColor Then
noColorCells = noColorCells + 1
End If
Next cel
Debug.Print "There are " & noColorCells & " non colored cells."
.Cells(startRow - 1, endCol + 2).Value = "Start Date"
.Cells(startRow - 1, endCol + 3).Value = "End Date"
'reDim the array to fit the colored cells
ReDim tDates(1 To noColorCells + 1)
i = 1 'index starts at 1, so set this to 1
For k = startRow To endRow
For o = startCol To endCol
If .Cells(k, o).Interior.ColorIndex = noColor And .Cells(k, endCol + 2) = "" Then
.Cells(k, endCol + 2).Value = .Cells(k, o).Value
ElseIf .Cells(k, o).Interior.ColorIndex = noColor And .Cells(k, endCol + 2) Then
i = i + i
.Cells(k, endCol + 3).Value = .Cells(k, o).Value
End If
' i = i + 1
Next o
i = i + 1
Next k
End With
MsgBox ("Done!")
End Sub
This sub will find the addresses of any colored cells. If you can explain more what you mean by "locate the beginning and the end of coloured rows in a table." I can tweak this. Can you post an image of a sample table maybe?
Edit: Per discussion below, try this in case there's not always data in the table, but you want the columns of the colored cells:
Sub findColoredBGCells()
Dim startRow As Integer, endRow As Integer, i As Integer, k As Integer, startCol As Integer, endCol As Integer
Dim cellColor As String, noColor As String
Dim ws As Worksheet
Set ws = ActiveSheet
noColor = -4142
With ws
'Get the starting row
startRow = .Cells(1, 1).End(xlDown).Row
endRow = .Cells(startRow, 1).End(xlDown).Row
' Since we know where the names start and end (less ONE for the "Names" part), let's count how many names we have
Dim noNames As Integer
noNames = endRow - startRow
If Not IsEmpty(.Cells(1, 1)) Then ' Get the first used column with data
startCol = 1
ElseIf IsEmpty(.Cells(1, 1)) Then
startCol = .Cells(1, 1).End(xlToRight).Column
End If
endCol = .Cells(1, startCol).End(xlToRight).Column
'Now we have our range, let's use it to loop for blank cells, and add those to an array
Dim coloredCells() As Variant
ReDim coloredCells(1 To noNames, 2)
Dim rng As Range, cel As Range
Set rng = .Range(.Cells(startRow, startCol), .Cells(endRow, endCol))
'rng.Select
'Now, count how many cells are not blank background
Dim cnt As Integer, celRow As Integer, lastCelRow As Integer
i = 1
lastCelRow = 2
For Each cel In rng
cel.Select
celRow = cel.Row
If cel.Row <> lastCelRow Then 'This is so we can change the first dimension in the array
k = k + 1
coloredCells(k, 0) = .Cells(cel.Row, 1).Value
i = 1
' i = i + 1
End If
If cel.Interior.ColorIndex <> noColor Then
cnt = cnt + 1
If i > 2 Then i = 2 'Since it's only two dimensions we need, only go up to '1'
' ReDim Preserve coloredCells(noNames, i) 'resize the array to hold the new column
coloredCells(k, i) = .Cells(1, cel.Column).Value
i = i + 1
End If
lastCelRow = celRow
Next cel
For k = 1 To UBound(coloredCells)
Debug.Print coloredCells(k, 0) & " Start Date: " & coloredCells(k, 1) & ", end date: " & coloredCells(k, 2) & "."
.Cells(2 + k, 2).Value = coloredCells(k, 1)
.Cells(2 + k, 3).Value = coloredCells(k, 2)
Next k
End With
MsgBox ("Done!")
End Sub