I am facing problem with removing duplicate from a single row. I want to loop through all rows in a range and remove duplicate from a single row without effecting rest of data in sheet. Here is sample data:
+---------------+------+------+------+---------------+---------------+
| name | num1 | num2 | mun3 | emial1 | email2 |
+---------------+------+------+------+---------------+---------------+
| ali zubair | 1 | 2 | 1 | az#az.com | az#az.com |
+---------------+------+------+------+---------------+---------------+
| tosif | 1 | 2 | 2 | t#zb.com | t#gb.com |
+---------------+------+------+------+---------------+---------------+
| qadeer satter | 3 | 2 | 3 | qs#mtm.com | star#mtn.com |
+---------------+------+------+------+---------------+---------------+
| asif | 4 | 3 | 2 | | |
+---------------+------+------+------+---------------+---------------+
| hamid | 1 | 5 | 2 | hamid#beta.ds | hamid#beta.ds |
+---------------+------+------+------+---------------+---------------+
Below code removes duplicate rows based on column 2, it is not applicable in my case.
ActiveSheet.Range("A1:f100").RemoveDuplicates Columns:=Array(2), Header:=xlYes
I have no idea how I can remove duplicate from a selected row range. So far I have the code that will loop through all rows in my data.
Sub removeRowDubs()
Dim nextRang As Range
Dim sCellStr As String, eCellStr As String
Dim dRow As Long
dRow = Cells(Rows.Count, 1).End(xlUp).Row
For dRow = 2 To dRow
sCellStr = Range("A" & dRow).Offset(0, 1).Address
eCellStr = Cells(dRow, Columns.Count).End(xlToLeft).Address
Set nextRang = Range(sCellStr, eCellStr)
Debug.Print nextRang.Address
Next
End Sub
So what I need is some code to do what I need inserted after below code.
Set nextRang = Range(sCellStr, eCellStr)
If there is a simple solution to this like ".RemoveDuplicates" then please let me know. As of now I am thinking of doing this through looping but it seems complex as I think I will need at least 3 "for each" loops and 3 "if conditions", 2 more row ranges and probably something else when I start doing it like that.
I hope I made my question clear and I will really appreciate your help. I am new at Excel VBA coding, your patience is needed..
So I also worked on the code to remove duplicates for rows. Below is my code, its working for me. It is complex and people over stackoverflow provided better code.
Sub removeRowDublicates()
Dim nextRang As Range ' Variables for
Dim sCellStr As String, eCellStr As String ' Going through all rows
Dim dRow As Long ' And selecting row range
dRow = Cells(Rows.Count, 1).End(xlUp).Row ' This code selects the
For dRow = 2 To dRow ' next row in the data
sCellStr = Range("A" & dRow).Offset(0, 1).Address
eCellStr = Cells(dRow, Columns.Count).End(xlToLeft).Address
Set nextRang = Range(sCellStr, eCellStr)
Dim aRange As Range, aCell As Range ' Variables for
Dim dubCheckCell As Range, dubCheckRange As Range ' Loops to remove
Dim dubCheckCell1 As Range ' Dublicates from
Dim columnNum As Integer ' Current row
Set aRange = nextRang
columnNum = Range("b2:f2").Columns.Count + 1
aRange.Select
For Each aCell In aRange 'Loop for selecting 1 cell, if not blank from range to check its value against all other cell values
If aCell.Value <> "" Then
Set dubCheckCell = aCell
Else
GoTo nextaCell 'If current cell is blank then go to next cell in range
End If
If dubCheckCell.Offset(0, 2).Value <> "" Then 'Selects range by offsetting 1 cell to right from current cell being checked for dublicate value
Set dubCheckRange = Range(dubCheckCell.Offset(, 1), dubCheckCell.Offset(, 1).End(xlToRight))
Else
Set dubCheckRange = Range(dubCheckCell.Offset(0, 1).Address)
End If
For Each dubCheckCell1 In dubCheckRange 'Loop that goes through all cells in range selected by above if-statement
Do While dubCheckCell1.Column <= columnNum
If dubCheckCell = dubCheckCell1 Then
dubCheckCell1.ClearContents
Else
End If
GoTo nextdubCheckCell1
Loop 'For do while
nextdubCheckCell1:
Next dubCheckCell1 'Next for dubCheckRange
nextaCell:
Next aCell 'Next for aRange
Next 'For drow
End Sub
Try the next code, please:
Sub testRemoveRowDuplicates()
Dim sh As Worksheet, rng As Range, lastRow As Long, i As Long
Set sh = ActiveSheet 'use here your sheet
lastRow = sh.Range("A" & Rows.Count).End(xlUp).row
For i = 2 To lastRow
Set rng = sh.Range("C" & i & ":D" & i)
rng.Replace rng.Cells(1, 1).Offset(0, -1).Value, "", xlWhole
Set rng = sh.Range("D" & i)
rng.Replace rng.Cells(1, 1).Offset(0, -1).Value, "", xlWhole
Set rng = sh.Range("F" & i)
rng.Replace rng.Cells(1, 1).Offset(0, -1).Value, "", xlWhole
Next i
End Sub
The above code assumes that a name cannot be duplicate in the email columns. It removes duplicates on each category (names and emails).
If you really need to check each value of the row, please, use the next variant:
Sub testRemoveRowDuplicatesBis()
Dim sh As Worksheet, rng As Range, lastRow As Long
Dim i As Long, j As Long
Set sh = ActiveSheet
lastRow = sh.Range("A" & Rows.Count).End(xlUp).row
For i = 2 To lastRow
For j = 3 To 6 'last column
Set rng = sh.Range(sh.Cells(i, j), sh.Cells(i, 6))
rng.Replace rng.Cells(1, 1).Offset(0, -1).Value, "", xlWhole
Next j
Next i
End Sub
You can use some VBA nested loops to do this - loop the rows, and then have two column loops to check the values of the cells:
Sub sRemoveRowDubs()
On Error GoTo E_Handle
Dim ws As Worksheet
Dim lngLastRow As Long
Dim lngLastCol As Long
Dim lngRow1 As Long
Dim lngCol1 As Long
Dim lngCol2 As Long
Set ws = Worksheets("Sheet4")
lngLastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
lngLastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
For lngRow1 = 1 To lngLastRow
For lngCol1 = 1 To lngLastCol
For lngCol2 = lngCol1 + 1 To lngLastCol
If ws.Cells(lngRow1, lngCol1) = ws.Cells(lngRow1, lngCol2) Then
ws.Cells(lngRow1, lngCol2) = ""
End If
Next lngCol2
Next lngCol1
Next lngRow1
sExit:
On Error Resume Next
Set ws = Nothing
Exit Sub
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "sRemoveRowDubs", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume sExit
End Sub
Regards,
If you can use formula and create a new table.
Array (CSE) Formula for Num1 column, enter the formula in formula bar, press control+Shift+Enter and then select the cell copy to Num2 and Num3. Then select all three cells and copy down.
=IFERROR(INDEX($B2:$D2,1,MATCH(0,COUNTIF($H2:H2,$B2:$D2),0)),"")
Array (CSE) Formula for email1 column, enter the formula in formula bar, press control+Shift+Enter and then select the cell copy to email2. Then select those two cells and copy down.
=IFERROR(INDEX($E2:$F2,1,MATCH(0,COUNTIF($K2:K2,$E2:$F2),0)),"")
Or maybe something like this?
Sub test()
Set rngName = Range("A2", Range("A" & Rows.Count).End(xlUp))
For Each cell In rngName
For i = 1 To 4
Set Rng = Range(cell.Offset(0, i + 1), Cells(cell.Row, 6))
Set c = Rng.Find(cell.Offset(0, i).Value, lookat:=xlWhole)
If Not c Is Nothing Then c.ClearContents
Next i
Next cell
End Sub
What I am thinking is selecting 1 cell from row then check it against
all other cells in the same row
The code assumes that there will be no blank in between row with value under column NAME (column A), and all the name value is unique. This is for the first loop.
The second loop is the how many cell in the same row to check, in this case there are 4 cells to check (num1, num2, num3 and email1) then so does the checking are 4 times ---> in the same row : check num1 against num2, num3, email1 and email2 ... check num2 against num3, email1 and email2 .... check num3 against email1 and email2... then finally check email1 against email2. On each check, if the same value is found, then the code put blank to the found cell.
Clear Duplicate Entries By Row
Copy the complete code into a standard module (e.g. Module1).
Only run the first Sub, the other two are being called.
Adjust the constants in the first Sub, including the workbook.
The Code
Option Explicit
Sub clearDups()
Const wsName As String = "Sheet1"
Const FirstRowAddress As String = "A2:F2"
Const LastRowColumn As Long = 1
Const Replacement As Variant = Empty
Dim wb As Workbook: Set wb = ThisWorkbook
' Define Data First Row Range.
Dim rng As Range: Set rng = wb.Worksheets(wsName).Range(FirstRowAddress)
' Define Data Range and write its values to Data Array.
Dim Data As Variant: getRangeValuesFR Data, rng, LastRowColumn
If IsEmpty(Data) Then Exit Sub
' In data array, clear duplicate values by row
' (from the top and from the left).
replaceDupsByRow Data, Replacement
' Write modified values from Data Array to Data Range.
rng.Resize(UBound(Data)).Value = Data
End Sub
Sub getRangeValuesFR(ByRef Data As Variant, _
ByRef FirstRowRange As Range, _
Optional ByVal LastRowColumn As Long = 1)
Dim rng As Range
If LastRowColumn = 0 Then GoSub LastRow0 Else GoSub LastRowN
If rng Is Nothing Then Exit Sub
If rng.Row < FirstRowRange.Row Then Exit Sub
Set rng = FirstRowRange.Resize(rng.Row - FirstRowRange.Row + 1)
If rng.Row > 1 Then
Data = rng.Value
Else
ReDim Data(1 To 1, 1 To 1): Data(1, 1) = rng.Value
End If
Exit Sub
LastRow0:
With FirstRowRange
Set rng = .Worksheet.Columns(.Column).Resize(, .Columns.Count) _
.Find("*", , xlValues, , xlByRows, xlPrevious)
End With
Return
LastRowN:
With FirstRowRange
Debug.Print .Columns(LastRowColumn).Address
Set rng = .Worksheet.Columns(.Columns(LastRowColumn).Column) _
.Find("*", , xlValues, , , xlPrevious)
End With
Return
End Sub
Sub replaceDupsByRow(ByRef Data As Variant, _
Optional ByVal Replacement As Variant = Empty)
Dim Curr As Variant, i As Long, j As Long, l As Long
For i = 1 To UBound(Data)
For j = 1 To UBound(Data, 2) - 1
Curr = Data(i, j + 1)
If Curr <> Replacement Then GoSub loopSubRows
Next j
Next i
Exit Sub
loopSubRows:
For l = 1 To j
If Curr = Data(i, l) Then
Data(i, j + 1) = Replacement: Exit For
End If
Next l
Return
End Sub
I have the following excel
I am trying the following code
> Sub fill_blanks()
Dim i As Long
i = 2 '
Do Until Range("B" & i) = ""
Range("B" & i).Select
If ActiveCell.FormulaR1C1 <> "" Then
Range("A" & i).Select
If ActiveCell.FormulaR1C1 = "" Then
Range("A" & i - 1).Copy
Range("A" & i).PasteSpecial Paste:=xlPasteValues
Else
i = i + 1
End If
Else
i = i + 1
End If
Loop
End Sub >
What I need to check is if the cell is not empty, then to keep its value, and if it was empty to check the first next not empty cell and the previous non empty cell in the same column, and if they have the same value, then to fill all the empty cells between with the same value, and if the two cells are not matching, then to return X.
So the result will be as following
But using the code , I am getting something different.
This what I get with this code
Find the last used row LastRow so we know where to stop.
Loop through your rows, when you come accross an epmty cell remember it FirstEmptyRow
Keep looping until you find data again, the row before is then LastEpmtyRow. Now we know the beginning and the end of the empty space.
Check if above the epmty space and below the empty space is the same date. If so fill it into the empty space otherwise fill in x.
So you end up with something like
Option Explicit
Public Sub FillData()
Const START_ROW As Long = 2 'define first data row
Const COL As String = "A" 'define the column
Dim ws As Worksheet 'define your worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim LastRow As Long 'find last used row in column A
LastRow = ws.Cells(ws.Rows.Count, COL).End(xlUp).Row
Dim FirstEmptyRow As Long, LastEpmtyRow As Long 'first and last empty row of a empty range
Dim iRow As Long
For iRow = START_ROW To LastRow
If ws.Cells(iRow, COL).Value = vbNullString And FirstEmptyRow = 0 Then
'found first row of an empty range
FirstEmptyRow = iRow
ElseIf ws.Cells(iRow, COL).Value <> vbNullString And FirstEmptyRow <> 0 Then
'found last row of an empty range
LastEpmtyRow = iRow - 1
'check if same date to fill either the date or x
If ws.Cells(FirstEmptyRow - 1, COL).Value = ws.Cells(LastEpmtyRow + 1, COL).Value Then
'fill date
ws.Range(ws.Cells(FirstEmptyRow, COL), ws.Cells(LastEpmtyRow, COL)).Value = ws.Cells(FirstEmptyRow - 1, COL).Value
Else
'fill x
ws.Range(ws.Cells(FirstEmptyRow, COL), ws.Cells(LastEpmtyRow, COL)).Value = "x"
End If
'reset variables
FirstEmptyRow = 0
LastEpmtyRow = 0
End If
Next iRow
End Sub
Image 1: Illustration of the process.
Currently, I want to automate some annoying work in excel and need some help.
I have a huge report which has 200k+ rows and about 500 columns and my task is to find out which cells of a column are never used.
This was fairly easy and I managed it to create a script that works for that so far.
But now I want to distinguish between row types and return for each row type whether there are columns that are never used.
My problem is that I do not know how to iterate through the contents of a cell, so that if the row type changes my script will count the empty columns for the next row type.
I hope you get the idea and can help me. You do not have to give me the full code but maybe an idea of how I can get to the solution :)
This is the vba code I currently have and that gives me the correct solution but without distinguishing between the rowtypes
Public row As Long
Public rowMax As Long
Public startRow As Integer
Public materialType As String
Public filter As String
Public col As Integer
Public colMax As Integer
Public isUsed As Boolean
Sub bestimmeObFelderGenutzt()
With Sheets("Sheet1")
filter = "I"
startRow = 2
rowMax = Sheets("Sheet1").Cells(.Rows.Count, "F").End(xlUp).row
colMax = Sheets("Sheet1").Cells(1, .Columns.Count).End(xlToLeft).Column
materialType = Sheets("Sheet1").Range(filter & startRow).Value
For col = 1 To colMax
Sheets("Sheet2").Cells(1, col + 2).Value = Sheets("Sheet1").Cells(1, col).Value
Next col
For row = 2 To rowMax
Sheets("Sheet2").Range("A" & row).Value = Sheets("Sheet1").Range("A" & row).Value
Sheets("Sheet2").Range("B" & row).Value = Sheets("Sheet1").Range("I" & row).Value
For col = 1 To colMax
If IsEmpty(Sheets("Sheet1").Cells(row, col)) = False Then
isUsed = True
Sheets("Sheet2").Cells(row, col + 2).Value = 1
Else:
Sheets("Sheet2").Cells(row, col + 2).Value = 0
End If
Next col
Next row
End With
End Sub
Sub findeUngenutzteSpalten()
With Sheets("Sheet2")
rowMax = Sheets("Sheet2").Cells(.Rows.Count, "F").End(xlUp).row
colMax = Sheets("Sheet2").Cells(1, .Columns.Count).End(xlToLeft).Column
Sheets("Sheet3").Cells(1, 1).Value = "Spaltenüberschrift"
Sheets("Sheet3").Cells(1, 2).Value = "Jemals benutzt?"
For col = 3 To colMax
isUsed = False
For row = 2 To rowMax
If Sheets("Sheet2").Cells(row, col).Value = 1 Then
Sheets("Sheet3").Range("A" & col - 1).Value = Sheets("Sheet2").Cells(1, col).Value
Sheets("Sheet3").Range("B" & col - 1).Value = "Ja"
GoTo WeiterCol
Else:
If row = rowMax Then
Sheets("Sheet3").Range("A" & col - 1).Value = Sheets("Sheet2").Cells(1, col).Value
Sheets("Sheet3").Range("B" & col - 1).Value = "Nein"
Else:
GoTo WeiterRow
End If
End If
WeiterRow:
Next row
WeiterCol:
Next col
End With
End Sub
If I understood your task correctly this should work, copy to your module and read comments:
Sub FindUnusedColumnsPerRow()
Dim cellRow As range, cellColumn As range
Dim rowRange As range, columnRange As range
Dim rowsCount As Long, columnsCount As Long
Dim insertRow As Long
Dim listOfEmptyColumns()
Dim i As Long, j As Long
Dim arrayCheck As Integer
With Sheets("Sheet1") ' I assume that this is your sheet with materials where you want to find unused columns
rowsCount = .Cells(Rows.Count, 6).End(xlUp).row ' get last row
columnsCount = .Cells(1, Columns.Count).End(xlToLeft).Column ' get last column
For Each cellRow In range(.Cells(2, 1), .Cells(rowsCount, 1)) ' going through all rows - here I suppose that material type is in the 1-st column, 1-st row is a header and data starts from 2-d row
For Each cellColumn In range(.Cells(cellRow.row, 2), .Cells(cellRow.row, columnsCount)) ' for each row looking through all columns - I suppose that data starts from 2-d column
If cellColumn = "" Then ' if the cell is empty.
ReDim Preserve listOfEmptyColumns(i) ' expanding array when needed
listOfEmptyColumns(i) = cellColumn.Column ' adding column number to an array, you may change it to = .cells(1,cellColumn.Column) to put a header name instead of column number
i = i + 1 ' increment the counter
End If
Next
On Error Resume Next ' a small trick to check whether the array with column numbers is empty
arrayCheck = UBound(listOfEmptyColumns) ' if the array is empty - an #9 "Subscript out of range" exception will be thrown
If Err.Number = 0 Then ' error number is 0 - means that there was no error
With Sheets("Sheet2") ' I suppose this is the sheet to store results
insertRow = .Cells(Rows.Count, 1).End(xlUp).row + 1 ' find the row to insert
.Cells(insertRow, 1) = cellRow.Value ' put the type to 1-st column
j = 2 ' start filling the row of the type with numbers of empty columns
For i = 0 To UBound(listOfEmptyColumns) ' populating data from array
.Cells(insertRow, j) = listOfEmptyColumns(i)
j = j + 1
Next
End With
End If
Err.Clear ' clearing the error, because it still holding an error information (if it was thrown)
On Error GoTo 0 ' don't forget to switch on normal error handling
Erase listOfEmptyColumns ' reset array before next row as the data is stored on sheet2
i = 0 ' reset the counter for further use
Next
End With
End Sub
I have some data in sheet called New, and my data are in column A to column K. However, column E to H are intentionally left blank for data analysis purposes and I have no header so my data starts from cell A1. Now in column A we have color in cell, I would like to delete any rows that aren't white so keep rows that don't have color in it.
I did some research but all of the codes I got online either delete the whole sheet or just pass through codes and nothing happens. Below are the ones I am currently using that doesn't do anything. I use F8 and still no error.
See image for my sample data and I am trying to get the results with cells that don't have any color in it. I tried to remove quotation mark for the color index but still it doesn't work.
Sub deleterow()
lastRow = Worksheets("New").Cells(Rows.Count, "A").End(xlUp).Row
For i = lastRow To 1 Step -1
If Worksheets("New").Cells(i, 1).Interior.ColorIndex <> "2" Then
Rows(i).EntireRow.Delete
i = i + 1
End If
Next I
End Sub
Try the code below:
Option Explicit
Sub deleterow()
Dim i As Long, LastRow As Long
With Worksheets("New")
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = LastRow To 1 Step -1
'If .Cells(i, 1).Interior.Color <> xlNone Then
' replace RGB(255, 255, 255) with the "white" color
If .Cells(i, 1).Interior.Color <> RGB(255, 255, 255) Then
.Rows(i).Delete
End If
Next i
End With
End Sub
Delete No Color Row
Union Version
Option Explicit
Sub DeleteNoColorRow()
Const cSheet As Variant = "Sheet1" ' Worksheet Name/Index
Const cFirstR As Integer = 1 ' First Row
Const cColumn As Variant = "A" ' Column Letter/Number
Dim rngU As Range ' Union Range
Dim lastRow As Long ' Last Row
Dim i As Long ' Row Counter
With ThisWorkbook.Worksheets(cSheet)
lastRow = .Cells(.Rows.Count, cColumn).End(xlUp).Row
For i = cFirstR To lastRow
If .Cells(i, cColumn).Interior.ColorIndex <> xlNone Then
If Not rngU Is Nothing Then
Set rngU = Union(rngU, .Cells(i, cColumn))
Else
Set rngU = .Cells(i, cColumn)
End If
End If
Next
End With
If Not rngU Is Nothing Then
rngU.EntireRow.Delete ' Hidden = True
Set rngU = Nothing
End If
End Sub
I need help with a VBA code that will look for certain criteria and if it matches place data from a different column into a another one.
If column C says "Circum + spa" and D says "100" then the values in row F need to move over two columns to H
until column C says "Circum + spa" and D says "0" (where it will stay in column F.)
finished result will looks like a snake.
The code I have started with this process with is:
Dim l As Long
With ActiveSheet
l = .Cells(.Rows.Count, "C").End(xlUp).Row
For i = 1 To l
If .Cells(i, "C").Value2 = "CIRCUM + SPA" And
.Cells(i, "D") = "100" Then
.Cells(i + 1, "F").Value = .Cells(i + 1, "H").Value
Next
End With
But currently it just makes one row down in column F empty... I have also attempted cut/paste and an offset but all I get are error messages.
I also know that using +1 isn't going to work in final result because I need it to grab everything until the other condition is met.
I have not started on that yet, but would appreciate any advise on a Do-Until loop.
I have attached pictures of what my worksheet looks like now vs what I need it to look like after the macro runs. Also, the rows that move will not always contain 4 cells, sometimes there will be more that's why I need the do until rather than a set range.
before[1]
after (2)
Try this
Sub Demo()
Dim ws As Worksheet
Dim cel As Range, fCell As Range, lCell As Range
Dim lastRow As Long
Dim flag As Boolean
Set ws = ThisWorkbook.Sheets("Sheet4") 'change Sheet4 to your data sheet
flag = False
With ws
lastRow = .Cells(.Rows.Count, "C").End(xlUp).Row 'last row with data in Column C
For Each cel In .Range("C2:C" & lastRow) 'loop through each cell in Column C
If UCase(cel.Value) = "CIRCUM + SPA" Then 'check if Command Name is "CIRCUM + SPA"
If cel.Offset(, 1).Value = 100 Then 'check if SP is 100
Set fCell = cel.Offset(1, 0) 'set first cell to be copied in fCell
flag = True
ElseIf cel.Offset(, 1).Value = 0 Then 'check if SP is 0
If flag Then 'move ahead only if ("CIRCUM + SPA" & 100) already found
Set lCell = cel.Offset(-1, 0) 'set last cell to be copied in lCell
Set rng = .Range(fCell, lCell).Offset(, 3) 'set range using fCell and lCell
rng.Cut rng.Offset(, 2) 'move data from Column F to Column H
flag = False
End If
End If
End If
Next cel
End With
End Sub