I have a large table of data with multiple columns that contain data for mostly triplicates of results. each row contains results from one data point for each subject. most of the subjects have three replicate results, but in some cases, there is only one or two. the sheet is sorted on the subject id column (which is my named range assigned to the variable rng used in the for loop).
this loop tests whether "targetcell" in the range "rng" (which is set to the named range in the sheet that contains the subject id), find the bottom row of any subjects duplicate or triplicate values, and then generates the mean in the newly inserted column:
Set rng = Range("clonesptid")
col = ActiveCell.Column
ActiveCell.Offset(0, 1).EntireColumn.Insert
anchor = col - rng.Column
'MsgBox "cell to test is " & rng(1)
'debugging message box to check where the ptid range is
'MsgBox "Range for ptID is " & rng.Column & " and the active cell address is " & ActiveCell.Address & " and the activecell col is " & anchor
For Each cell In rng
'uncomment the line below to check the cell addresses
' str = str & Cell.Address & " contains " & Cell.Value & "(above=" & Cell.Offset(-1, 0).Value & " below=" & Cell.Offset(1, 0).Value & vbNewLine
' MsgBox "What is our test value?" & vbNewLine & cell.Value
If IsEmpty(cell.Value) = True Then Exit For
targetcell = cell.Value
If cell.Row > 2 Then twoup = cell.Offset(-2, 0).Value
If cell.Row > 1 Then oneup = cell.Offset(-1, 0).Value
onedown = cell.Offset(1, 0).Value
If IsEmpty(targetcell) = False Then
If cell.Row = 1 Then
'adds title with means to first header row
Cells(1, col + 1).Value = Cells(1, col).Value & " mean"
ElseIf cell.Row = 2 And targetcell <> oneup And targetcell <> onedown Then
'test the first value, if unique mean = the value of the cell
cell.Offset(0, anchor + 1).Value = cell.Offset(0, anchor).Value
ElseIf targetcell <> oneup And targetcell <> onedown Then
'for all the rest of the cells in the range, this condition tests for singlets
cell.Offset(0, anchor + 1).Value = cell.Offset(0, anchor).Value
ElseIf targetcell = oneup And targetcell <> twoup And targetcell <> onedown Then
'test for two values
cell.Offset(0, anchor + 1).Value = (cell.Offset(0, anchor).Value + cell.Offset(-1, anchor).Value) / 2
ElseIf targetcell = oneup And targetcell = twoup And targetcell <> onedown Then
'test for three values
cell.Offset(0, anchor + 1).Value = (cell.Offset(0, anchor).Value + cell.Offset(-1, anchor).Value + cell.Offset(-2, anchor).Value) / 3
Else
'this is the first or second replicate of duplicates or triplicates, but not yet the bottom value
cell.Offset(0, anchor + 1).Value = ""
End If
End If
Next
If you have a specific operation like "find all same values up and down" then it's best to move that to a separate method.
Untested:
Sub tester()
Dim rng As Range, cell As Range, dups As Range
Dim lastDup As Range, col As Long, anchor As Long
col = ActiveCell.Column
Cells(1, col + 1).EntireColumn.Insert
Cells(1, col + 1).Value = "Mean"
Set rng = Range("clonesptid")
anchor = col - rng.Column
Set cell = rng.Cells(1)
Do While Len(cell.Value) > 0
Set dups = DupsRange(cell) 'get contiguous range with same value in column
Set lastDup = dups.Cells(dups.Cells.Count)
'calculate your average here
lastDup.Offset(0, anchor + 1) = Application.Average(dups.Offset(0, anchor))
Set cell = lastDup.Offset(1, 0) 'next set
Loop
End Sub
'Given a cell, check up and down to find
' the contiguous same-value range
Public Function DupsRange(c As Range) As Range
Dim cStart As Range, cEnd As Range
If Len(c.Value) = 0 Then Exit Function
Set cStart = c
Set cEnd = c
Do While cStart.Row > 1
If cStart.Offset(-1, 0).Value = c.Value Then _
Set cStart = cStart.Offset(-1, 0) Else Exit Do
Loop
Do While cEnd.Row < Rows.Count
If cEnd.Offset(1, 0).Value = c.Value Then _
Set cEnd = cEnd.Offset(1, 0) Else Exit Do
Loop
Set DupsRange = c.Parent.Range(cStart, cEnd)
End Function
Related
I have the workbook below that shows clock in and out each day for each employee and shop. I was able to find the cell and if they are late after 8:00 am then it will debug.print that the employee was late. The problem I have now is that sometimes the employee goes on a lunch break and its reading the second time clocked in as if he was late. I would like to print notes on the sheet that will tell me for example "Nathan was late on Monday, 8:47:43 AM" and if he left during the day and came back. For example "Trent left Monday on 12:54 PM and came back on 1:28 PM". I am just having trouble reading through multiple times on the same day. The below code is what I have so far. Any ideas?
Sheet :
Sub TestFindAll()
Dim SearchRange As Range
Dim FindWhat As Variant
Dim FoundCells As Range
Dim FoundCell As Range
Dim LastRowA As Long, LastRowJ As Long
Dim WS1 As Worksheet
Set WS1 = ThisWorkbook.Worksheets("DailyTimeSheet")
LastRowJ = WS1.Range("J" & WS1.Rows.Count).End(xlUp).Row
Debug.Print LastRowJ
Dim firstAddress As String
With WS1
Dim tbl As ListObject: Set tbl = .Range("DailyTime").ListObject
Set SearchRange = tbl.ListColumns("EmployeeName").Range
End With
For t = 2 To LastRowJ
FindWhat = WS1.Range("J" & t)
Set FoundCells = SearchRange.Find(What:=FindWhat, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows)
If Not FoundCells Is Nothing Then
firstAddress = FoundCells.Address
Debug.Print "Found " & FoundCells.Value & " " & FoundCells.Offset(0, 2).Value
Do
If Not FoundCells.Offset(0, 2).Value = "Sat" And FoundCells.Offset(0, 5).Value < TimeValue("18:00:00") Then
Debug.Print FoundCells.Value & " left early on " & FoundCells.Offset(0, 2) & " at " & TimeValue(Format(FoundCells.Offset(0, 5).Value, "hh:mm:ss"))
End If
Set FoundCells = SearchRange.FindNext(FoundCells)
' Debug.Print "Found " & FoundCells.Value & " " & FoundCells.Offset(0, 2)
Loop While Not FoundCells Is Nothing And FoundCells.Address <> firstAddress
End If
Next
End Sub
Use a Dictionary Object with names as key to identify the first in or last out time of the day.
Option Explicit
Sub macro()
Dim lastrow As Long, r As Long, dt As String
Dim dict As Object, key, n As Long, c As Range
Set dict = CreateObject("Scripting.Dictionary")
With Sheet1 'ThisWorkbook.Worksheets("DailyTimeSheet")
.Cells.Interior.Pattern = xlNone
lastrow = .Cells(.Rows.Count, "J").End(xlUp).Row
' check in times
For Each c In .Range("J2:J" & lastrow).Cells
dt = Format(c.Offset(, 2), "yyyy-mm-dd")
key = Trim(c.Value)
' initialise
If Not dict.exists(key) Then
dict.Add key, "0000-00-00"
End If
' is this first for the day
If dict(key) <> dt Then
If c.Offset(, 2).Value <> "Sat" And _
c.Offset(, 4) > TimeValue("08:00:00") Then
c.Offset(, 4).Interior.Color = RGB(255, 255, 0)
n = n + 1
End If
End If
dict(key) = dt ' store
Next
' reverse scan to check out times
dict.RemoveAll
For r = lastrow To 2 Step -1
Set c = .Cells(r, "J")
dt = Format(c.Offset(, 2), "yyyy-mm-dd")
key = Trim(c.Value)
' initialise
If Not dict.exists(key) Then
dict.Add key, "0000-00-00"
End If
'is the last for the day
If dict(key) <> dt Then
If c.Offset(, 2).Value <> "Sat" And _
(c.Offset(, 5) < TimeValue("18:00:00")) Then
c.Offset(, 5).Interior.Color = RGB(255, 255, 0)
n = n + 1
End If
End If
dict(key) = dt ' store
Next
MsgBox n & " cells highlighted", vbInformation
End With
End Sub
I have a sheet with details regarding orders. In column G a specific value indicates what container (shipping container) the order is packed in.screenshot
I would like all duplicate container no. to be highlighted with different colors and their row with them.
Meaning: that when I have "container no. X" the entire row connected to X is one color and rows connected to "container no. Y" is another color and so on.
I would also like an automatic update of colors when something changes or when I hit "update values" in the data bar
Blank cells in column G should not to be colored.
Is this possible and if so, can someone help me out. I am very much a beginner with VBA.
Sub ColorCompanyDuplicates()
'Updateby Extendoffice
Dim xRg As Range
Dim xTxt As String
Dim xCell As Range
Dim xChar As String
Dim xCellPre As Range
Dim xCIndex As Long
Dim xCol As Collection
Dim I As Long
On Error Resume Next
If ActiveWindow.RangeSelection.Count > 1 Then
xTxt = ActiveWindow.RangeSelection.AddressLocal
Else
xTxt = ActiveSheet.UsedRange.AddressLocal
End If
Set xRg = Application.InputBox("please select the data range:", "Kutools for Excel", xTxt, , , , , 8)
If xRg Is Nothing Then Exit Sub
xCIndex = 2
Set xCol = New Collection
For Each xCell In xRg
On Error Resume Next
If xCell.Value <> "" Then
xCol.Add xCell, xCell.Text
If Err.Number = 457 Then
xCIndex = xCIndex + 1
Set xCellPre = xCol(xCell.Text)
If xCellPre.Interior.ColorIndex = xlNone Then xCellPre.Interior.ColorIndex = xCIndex
xCell.Interior.ColorIndex = xCellPre.Interior.ColorIndex
ElseIf Err.Number = 9 Then
MsgBox "Too many duplicate companies!", vbCritical, "Kutools for Excel"
Exit Sub
End If
On Error GoTo 0
End If
Next
End Sub
This code does number 1 and 3.
Also, it only uses bright colors.
Sub ColorCompanyDuplicates()
Dim row_start As Long, last_row As Long, color_index As Long
Dim R As Long, last_col As Long, col As Long
Dim used_range As Range, paint_row As Boolean
'CONFIG -------------------------
row_start = 5 'first row of the data set
paint_row = True 'set to false if you want to paint only the column
'--------------------------------
color_index = 33
Set used_range = ActiveSheet.UsedRange
last_col = _
used_range.Columns.Count + used_range.Column - 1
last_row = _
Cells(Rows.Count, 7).End(xlUp).Row
'clean existing rows in container names
For R = row_start To last_row
If Range("g" & R) <> "" Then
Range("g" & R).Value = Split(Range("g" & R).Value, " ")(0)
End If
Next R
'paint duplicates
For R = row_start To last_row
'if the next container name is the same and is not null then paint
If Cells(R, 7) = Cells(R + 1, 7) And Cells(R, 7) <> "" Then
If paint_row Then
For col = used_range.Column To last_col
Cells(R, col).Interior.ColorIndex = color_index
Next col
Else
For col = used_range.Column To last_col
Cells(R, col).Interior.ColorIndex = 0
Next col
Cells(R, 7).Interior.ColorIndex = color_index
End If
'FOR THE LAST ONE in the group
'if previews container name is the same and is not null then paint
ElseIf Cells(R, 7) = Cells(R - 1, 7) And Cells(R, 7) <> "" Then
If paint_row Then
For col = used_range.Column To last_col
Cells(R, col).Interior.ColorIndex = color_index
Next col
Else
For col = used_range.Column To last_col
Cells(R, col).Interior.ColorIndex = 0
Next col
Cells(R, 7).Interior.ColorIndex = color_index
End If
'and change color for the next group
color_index = color_index + 1
'avoid dark colors
If color_index = 46 Then
color_index = 33
End If
End If
Next R
'add row numbers to containers name
For R = row_start To last_row
If Range("g" & R) <> "" Then
Cells(R, 7) = Cells(R, 7) & " ROW:" & R
End If
Next R
End Sub
I would suggest for number 2 just create a refresh button or a command shortcut.
I am trying to add the value of a cell in an array, but i am getting a type mismatch error in my code. Why is this happening?
Dim rng As Range
Dim cell As Range
Dim arr As Variant
Set rng = Range("panel_is_on")
For Each cell In rng
If cell.Value2 = "On" Then
If cell.Offset(0, -1).Value2 = "ISJ" Or cell.Offset(0, -1).Value2 = "BSJ" Then
arr(i) = cell.Offset(0, -3).Value2
i = i + 1
End If
End If
Next cell
This works for me:
For Each cell In rng
If cell.Value2 = "On" Then
If cell.Offset(0, -1).Value2 = "ISJ" Or cell.Offset(0, -1).Value2 = "BSJ" Then
i = i + 1
ReDim Preserve arr(1 To i)
arr(i) = cell.Offset(0, -3).Value2
End if
Next cell
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
What I am trying to do is get my macro to search the data in Column "E". If the cell value contains "string", then I would like to offset by one column to the left, verify if, in the new selected cell, cell value contains "". If the new selected cell value is "" then background color is 19, if it contains "*" then background color is -4142.
Here is the code I have so far:
Sub Set_Background_Color ()
lRow = Range("E" & Rows.Count).End(xlUp).Row
Set MR = Range("E2:E" & lRow)
For Each cell In MR
If cell.Value = "X" Then cell.Offset(, -1).Interior.ColorIndex = 19
Next
End Sub
I can't seem to figure out how to embed a new If statement after the Offset and before the .Interior.ColorIndex
I have tried this mess but you will see immediately that it does not work.
If cell.Value = "X" Then
ElseIf cell.Offset(, -1).Value = "" Then cell.Interior.ColorIndex = 19
Else: cell.Interior.ColorIndex = -4142
Any help is greatly apreciated!
So close!
Sub Set_Background_Color ()
Dim lRow As Long
Dim MR As Range
Dim cel As Range
lRow = Range("E" & Rows.Count).End(xlUp).Row
Set MR = Range("E2:E" & lRow)
For Each cel In MR
If cel.Value = "string" Then
If cel.Offset(, -1).Value = "" Then
cel.Offset(, -1).Interior.ColorIndex = 19
ElseIf cel.Offset(, -1).Value = "*" Then
cel.Offset(, -1).Interior.ColorIndex = -4142
End If
End If
Next
End Sub
If by contains "*" you mean "has any content" then:
If cell.Value = "X" Then
cell.Interior.ColorIndex = IIf(Len(cell.Offset(0, -1).Value) = 0, 19, xlNone)
End If