I need to loop over all rows (except my header rows) and merge all cells with the same value in the same column. Before I do this I already made sure, that the column is sorted.
So I have some setup like this.
a b c d e
1 x x x x
2 x x x x
2 x x x x
2 x x x x
3 x x x x
3 x x x x
And need this
a b c d e
1 x x x x
2 x x x x
x x x x
x x x x
3 x x x x
x x x x
With my code I achieved to merge two equal cells. Instead I need to merge all equal cells.
Dim i As Long
For i = 2 To Range("A" & Rows.Count).End(xlUp).Row
If Cells(i, 1) <> "" Then
If Cells(i, 1) = Cells(i - 1, 1) Then
Range(Cells(i, 1), Cells(i - 1, 1)).Merge
End If
End If
Next i
This method does not use merged cells, but achieves the same visual effect:
Say we start with:
Running this macro:
Sub HideDups()
Dim N As Long, i As Long
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = N To 3 Step -1
With Cells(i, 1)
If .Value = Cells(i - 1, 1).Value Then
.Font.ColorIndex = 2
End If
End With
Next i
End Sub
will produce this result:
NOTE:
No cells are merged. This visual effect is the same because consecutive duplicates in the same column are "hidden" by having the colour of the font be the same as the colour of the cell background.
I know this is an old thread, but I needed something similar. Here's what I came up with.
Sub MergeLikeCells()
Dim varTestVal As Variant
Dim intRowCount As Integer
Dim intAdjustment As Integer
ActiveSheet.Range("A1").Select
'Find like values in column A - Merge and Center Cells
While Selection.Offset(1, 0).Value <> ""
'If instead you have blanks in the column, change the prev statement to While Selection.Offset(1, 0).Value <> "." and add "." to the last 2 rows of the data
intRowCount = 1
varTestVal = Selection.Value
While Selection.Offset(1, 0).Value = varTestVal
intRowCount = intRowCount + 1
Selection.Offset(1, 0).Select
Selection.ClearContents
Wend
intAdjustment = (intRowCount * -1) + 1
Selection.Offset(intAdjustment, 0).Select
Selection.Resize(intRowCount, 1).Select
With Selection
.Merge
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
End With
Selection.Offset(1, 0).Resize(1, 1).Select
Wend
End Sub
My solution as below, have a good day!
Sub MergeSameValue()
Application.DisplayAlerts = False
Dim LastRow As Integer
Dim StartRow As Integer
StartRow = 2
LastRow = Range("A" & Rows.Count).End(xlUp).Row
Dim StartMerge As Integer
StartMerge = StartRow
For i = StartRow + 1 To LastRow
If Cells(i, 1) <> "" Then
If Cells(i, 1) <> Cells(i - 1, 1) Then
Range(Cells(i - 1, 1), Cells(StartMerge, 1)).Merge
StartMerge = i
End If
End If
Next i
End Sub
Related
I currently have a data set that looks like the following:
A B C D E F G
1 x x x x x x *
2 a a a a a a
3 c c c c c c %
I need code to copy paste rows at the bottom of the data set based on if there's text in column. I would then need the text in column G to appear in column F while everything else in the row stays the same. For example, the result would be:
A B C D E F G
1 x x x x x x *
2 a a a a a a
3 c c c c c c %
4 x x x x x *
5 c c c c c %
My code currently looks like this:
Public Sub CopyRows()
Sheets("Exposure Distribution").Select
' Find the last row of data
FinalRow = Cells(Rows.Count, 1).End(xlUp).Row
' Loop through each row
For x = 2 To FinalRow
' Decide if to copy based on column H
ThisValue = Cells(x, 8).Value
If Application.WorksheetFunction.IsText(ThisValue) = "True" Then
Cells(x, 1).Resize(1, 33).Copy
Sheets("Exposure Distribution").Select
NextRow = Cells(Rows.Count, 1).End(xlUp).Row + 1
Cells(NextRow, 1).Select
ActiveSheet.Paste
Sheets("Exposure Distribution").Select
End If
ThisValue = Cells(x, 9).Value
If Application.WorksheetFunction.IsText(ThisValue) = "True" Then
Cells(x, 1).Resize(1, 33).Copy
Sheets("Exposure Distribution").Select
NextRow = Cells(Rows.Count, 1).End(xlUp).Row + 1
Cells(NextRow, 1).Select
ActiveSheet.Paste
Sheets("Exposure Distribution").Select
End If
ThisValue = Cells(x, 10).Value
If Application.WorksheetFunction.IsText(ThisValue) = "True" Then
Cells(x, 1).Resize(1, 33).Copy
Sheets("Exposure Distribution").Select
NextRow = Cells(Rows.Count, 1).End(xlUp).Row + 1
Cells(NextRow, 1).Select
ActiveSheet.Paste
Sheets("Exposure Distribution").Select
End If
Next x
End Sub
However I don't know how to accomplish the final part of what I'm looking for, which is moving data from column G to column F based on if there's text in `column G`.
See if this helps:
Sub CopyPasteWithConditions()
Dim wb As Workbook: Set wb = ActiveWorkbook 'declare and set the workbook
Dim ws As Worksheet: Set ws = wb.Sheets("SheetNameHere") 'declare and set the worksheet
Dim lRow As Long: lRow = ws.Cells(Rows.Count, "A").End(xlUp).Row 'get the last row of current data
Dim cntTxts As Long: cntTxts = WorksheetFunction.CountA(Range("G1:G" & lRow)) 'get the number of times there is any text in G
Dim arrData As Variant: arrData = ws.Range("A1:G" & lRow + cntTxts) 'create an array of current data + number of rows required for the copied data
Dim R As Long, C As Long, X As Long
For R = LBound(arrData) To lRow 'for each row in current data
If arrData(R, 7) <> "" Then 'if there is any text in G
X = X + 1
For C = LBound(arrData, 2) To UBound(arrData, 2) - 1 'for each column in data, except last
If C = 6 Then 'if we are on the last column, get the extra text instead
arrData(lRow + X, C) = arrData(R, 7) 'add the value to the row equal to last row + value of X (pretty much the next free row)
Else 'else the other values
arrData(lRow + X, C) = arrData(R, C) 'add the value to the row equal to last row + value of X (pretty much the next free row)
End If
Next C
End If
Next R
ws.Range("A1:G" & lRow + cntTxts) = arrData 'put the data back on the sheet
End Sub
I've got a function which merges cells in table if whole range has the same value (eg. if A1:G1 is equal to A2:B2 it will merge cells like A1&A2, B1&B2 etc. More here: How to check if two ranges value is equal)
Now I would like, to change color on table created by that funcion, like first row (doesn't matter if merged or no) filled with color, second blank etc. but I have no idea whether I should color it with merging function or create another which will detect new table with merged rows as one etc. Below is my code:
Sub test()
Dim i As Long, j As Long, k As Long, row As Long
row = Cells(Rows.Count, 2).End(xlUp).row
k = 1
For i = 1 To row Step 1
If Cells(i, 1).Value = "" Then Exit For
If Join(Application.Transpose(Application.Transpose(Range(Cells(i, 1), Cells(i, 3)))), Chr(0)) <> Join(Application.Transpose(Application.Transpose(Range(Cells(i + 1, 1), Cells(i + 1, 3)))), Chr(0)) Then
If i <> k Then
For j = 1 To 3 Step 1
Application.DisplayAlerts = False
Range(Cells(i, j), Cells(k, j)).Merge
Application.DisplayAlerts = True
Next j
End If
k = i + 1
End If
Next i
End Sub
Try:
Option Explicit
Sub test1()
Dim LastColumn As Long, LastRow As Long, i As Long
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
LastColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
For i = 2 To LastRow Step 2
.Range(Cells(i, 1), .Cells(i, LastColumn)).Interior.Color = vbGreen '<- You could change the color
Next i
End With
End Sub
Before:
After:
Edited Solution:
Option Explicit
Sub test1()
Dim rng As Range
With ThisWorkbook.Worksheets("Sheet1")
Set rng = .UsedRange
.ListObjects.Add(xlSrcRange, rng, , xlYes).Name = "Table1"
.ListObjects("Table1").TableStyle = "TableStyleLight3"
End With
End Sub
Result:
So, after some time I've figured it out by myself. Below is the code:
Dim i As Long, j As Long, k As Long, l As Long, c As Integer
row = Cells(Rows.Count, 2).End(xlUp).row
k = 7
c = 1
For i = 7 To row Step 1
If Join(Application.Transpose(Application.Transpose(Range(Cells(i, 1), Cells(i, 3)))), Chr(0)) <> Join(Application.Transpose(Application.Transpose(Range(Cells(i + 1, 1), Cells(i + 1, 3)))), Chr(0)) Then
If i <> k Then
For j = 1 To 3 Step 1
Application.DisplayAlerts = False
Range(Cells(i, j), Cells(k, j)).Merge
Application.DisplayAlerts = True
Next j
End If
Select Case c
Case 0
Range(Cells(k, 1), Cells(k, 3)).Interior.Color = xlNone
c = 1
Case 1
For l = 0 To i - k Step 1
Range(Cells(k + l, 1), Cells(k + l, 3)).Interior.Color = RGB(217, 225, 242)
Next l
c = 0
End Select
k = i + 1
End If
Next i
I search any text within Worksheet2 and display the results in ListBox1.
Private Sub SearchButton_Click()
'ListBox1.Clear
ListBox1.RowSource = ""
ListBox1.ColumnHeads = False
'listbox column headers
Me.ListBox1.AddItem
For A = 1 To 8
Me.ListBox1.List(0, A - 1) = Sheet2.Cells(1, A)
Next A
Me.ListBox1.Selected(0) = True
'Populating listbox from search
Dim i As Long
For i = 2 To Sheet2.Range("A100000").End(xlUp).Offset(1, 0).Row
For j = 1 To 8
H = Application.WorksheetFunction.CountIf(Sheet2.Range("A" & i, "H" & i), Sheet2.Cells(i, j))
If H = 1 And LCase(Sheet2.Cells(i, j)) = LCase(Me.TextBox2) Or H = 1 And _
Sheet2.Cells(i, j) = Val(Me.TextBox2) Then
Me.ListBox1.AddItem
For X = 1 To 8
Me.ListBox1.List(ListBox1.ListCount - 1, X - 1) = Sheet2.Cells(i, X)
Next X
End If
Next j
Next i
End Sub
I want to search multiple worksheets instead but don't know how to achieve this without changing the code completely.
You're going to have to change the reference to Sheet2 if you want to look at multiple sheets. There's no way around that. But, it will make your code more flexible. Start by doing this:
Private Sub SearchButton_Click()
'ListBox1.Clear
ListBox1.RowSource = ""
ListBox1.ColumnHeads = False
'listbox column headers
Me.ListBox1.AddItem
For A = 1 To 8
Me.ListBox1.List(0, A - 1) = Sheet2.Cells(1, A)
Next A
Me.ListBox1.Selected(0) = True
Dim ws As Worksheet 'This is the new line of code where you define your worksheet
Set ws = ActiveWorkbook.Sheet2 'Replace all references below to Sheet2 with this
'Populating listbox from search
Dim i As Long
For i = 2 To ws.Range("A100000").End(xlUp).Offset(1, 0).Row
For j = 1 To 8
H = Application.WorksheetFunction.CountIf(ws.Range("A" & i, "H" & i), Sheet2.Cells(i, j))
If H = 1 And LCase(Sheet2.Cells(i, j)) = LCase(Me.TextBox2) Or H = 1 And _
ws.Cells(i, j) = Val(Me.TextBox2) Then
Me.ListBox1.AddItem
For X = 1 To 8
Me.ListBox1.List(ListBox1.ListCount - 1, X - 1) = Sheet2.Cells(i, X)
Next X
End If
Next j
Next i
End Sub
Now that you're generalized your Sub, you can modify the value of ws to repeat the code as much as you need to. If it is every sheet in your workbook, you can use a For Each loop, like
For Each ws In ActiveWorkbook
'All your code for the ws here
Next ws
Or, you can define the worksheets in an array beforehand.
Dim SheetList(0 to 2) As String
Dim k As Integer
SheetList(0) = "Sheet 2 Name"
SheetList(1) = "Sheet 4 Name"
SheetList(2) = "Sheet 3 Name"
SheetList(3) = "Sheet 6 Name"
For k = LBound(SheetList) To UBound(SheetList)
ws = ActiveWorkbook.Sheets(SheetList(k))
'The rest of your code from above
Next k
You didn't specify in your question what kind of sheets how many, or how they are organized. But, these options should be enough to get you where you are trying to go.
I've got a workbook with one "source" worksheet and several destination sheets. essentially the source sheet contains information that I need to match and split out to team members. I've got the following code that freezes excel on me like it's stuck in a never ending loop. the VBA exists on the source worksheet's VBA.
Sub SearchForString()
Dim ws As Worksheet
Dim x As Integer
Dim y As Integer
Dim z as Integer
x = 1
y = 1
z = 4 'in this case we are looking at column D as the last non-criteria column
For Each ws In Worksheets(Array("Sheet1", "Sheet2", "Sheet3", "Sheet4", "Sheet5", "Sheet6", "Sheet7"))
x = 1 'setting back to row 1 to grab headers
y = 1
ws.UsedRange.ClearContents
Worksheets(ws.Name).Cells(y, 1) = Cells(x, 1)
Worksheets(ws.Name).Cells(y, 1).Font.Bold = True
Worksheets(ws.Name).Cells(y, 2) = Cells(x, 2)
Worksheets(ws.Name).Cells(y, 2).Font.Bold = True
Worksheets(ws.Name).Cells(y, 3) = Cells(x, 3)
Worksheets(ws.Name).Cells(y, 3).Font.Bold = True
Worksheets(ws.Name).Cells(y, 4) = Cells(x, 4)
Worksheets(ws.Name).Cells(y, 4).Font.Bold = True
'begin the copy loop
x = 2 'setting forward to the first row to start evaluating for copy
y = 2
z = z + 1 'increments along the columns we are matching in the array
Do while Cells(x, 1) <> vbNullString 'make sure we have an active row
If Cells(x, z) = "Yes" Then ' looks for row plus column for match
Do While Worksheets(ws.Name).Cells(y, 2) <> vbNullString
y = y + 1 'setting the row to start pasting
Loop
Worksheets(ws.Name).Cells(y, 1) = Cells(x, 1)
Worksheets(ws.Name).Cells(y, 2) = Cells(x, 2)
Worksheets(ws.Name).Cells(y, 3) = Cells(x, 3)
Worksheets(ws.Name).Cells(y, 4) = Cells(x, 4)
x = x + 1 'increment to next row
End If
Loop
Next ws
End Sub
I can't spot what would be sticking it into an endless loop like it seems to be in. Is anything glaring to anyone?
If Cells(x, z) <> "Yes", x never gets incremented and Cells(x, 1) <> vbNullString stays true
T'm trying to format n ranges of 4 columns like below, expanding to the right and separated by a blank column (col "E"). The range 2 starts at column "F".
range 1
A B C D ...
X Action1 X X
-
-
X Action2 X X
X Action3 X X
#N/A #N/A #N/A
For each range, I want to remove rows (of 4 columns) containing "-" on the second column or "#N/A" on any column of the range, expecting this result :
range 1
A B C D ...
X Action1 X X
X Action2 X X
X Action3 X X
This is a part of a VBA macro so I won't use manual autofilters. On top, autofiltering would remove also rows from other ranges, which is not expected.
I'm trying this code at least for testing on the 1st block, even not working :
Dim Rng As Range
Set Rng = Range("A4", "D53")
If Not Rng(, 2).Value = "-" Then
Rng.Delete Shift:=xlUp
End If
edit : I guess the answer may not be far away from this but I can't manage it properly.
Lost in VBA, some help would be great, thx in advance
EDIT: if it may help someone, I ended up with this working code thx to the below hints :
Dim iRows, iCols, NbLig, x, BlockSize, BlockOffset, MyOffsetBtwnBlocks, CountBlocks As Integer
BlockSize = 4
NbLig = Range("A3").SpecialCells(xlCellTypeLastCell).Row
CountBlocks = 0
For iCols = 2 To NbCol Step BlockSize + 1
iRows = Range(Cells(3, iCols), Cells(NbLig, iCols + BlockSize).End(xlToLeft)).Rows.Count
For x = iRows To 3 Step -1
If Application.WorksheetFunction.IsNA(Cells(x, iCols + 1)) Then
Application.Intersect(Cells(x, iCols + 1).EntireRow, _
Range(Cells(3, iCols), Cells(3, iCols + BlockSize)).EntireColumn).Delete
ElseIf Application.WorksheetFunction.IsNA(Cells(x, iCols + 2)) Then
Application.Intersect(Cells(x, iCols + 2).EntireRow, _
Range(Cells(3, iCols), Cells(3, iCols + BlockSize)).EntireColumn).Delete
ElseIf Cells(x, iCols + 1).Value = "-" Then
Application.Intersect(Cells(x, iCols + 1).EntireRow, _
Range(Cells(3, iCols), Cells(3, iCols + BlockSize)).EntireColumn).Delete
End If
CountBlocks = CountBlocks + 1
Next x
Next iCols
This should do you:
Sub RemoveX()
Dim iRows As Integer
Dim x As Integer
Application.ScreenUpdating = False
iRows = Range("A1").CurrentRegion.Rows.Count
For x = iRows To 1 Step -1
If Application.WorksheetFunction.IsNA(Cells(x, 2)) Then
Application.Intersect(Cells(x, 2).EntireRow, _
Range("A1:D1").EntireColumn).Delete
ElseIf Cells(x, 2).Value = "-" Then
Application.Intersect(Cells(x, 2).EntireRow, _
Range("A1:D1").EntireColumn).Delete
End If
Next x
Application.ScreenUpdating = True
End Sub
CurrentRegion is the region obtained if you click into A1 and press Ctrl-A.
If could be tidied up a little (using Range references and not using EntireRow or -Column) but it works.