VBA get unique value from range and result input every second row - excel

I have two macros that I would like to combine but somehow its not going well...
I want a macro that will get only unique values from a range and input them into another sheet every second row starting from row no 3
Could anyone tell me how should I combine those two macros?
I have tried to change .Font.Size = 20 with Application.Transpose(objDict.keys) but it didn't work.
Sub UniqueValue()
Dim X
Dim objDict As Object
Dim lngRow As Long
Set objDict = CreateObject("Scripting.Dictionary")
X = Application.Transpose(Range([a1], Cells(Rows.Count, "A").End(xlUp)))
For lngRow = 1 To UBound(X, 1)
objDict(X(lngRow)) = 1
Next
Range("F1:F" & objDict.Count) = Application.Transpose(objDict.keys)
End Sub
Sub EverySecond()
Dim EndRow As Long
EndRow = Range("A" & Rows.Count).End(xlUp).Row
For ColNum = 5 To EndRow Step 2
Range(Cells(ColNum, 2), Cells(ColNum, 2)).Font.Size = 20
Next ColNum
End Sub

Copy Unique Values to Every Other Row
Option Explicit
Sub UniqueEveryOther()
Const sName As String = "Sheet1"
Const sFirstCellAddress As String = "A2"
Const dName As String = "Sheet2"
Const dFirstCellAddress As String = "A2"
Dim wb As Workbook: Set wb = ThisWorkbook
' Reference the source range.
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim srg As Range
Dim srCount As Long
With sws.Range(sFirstCellAddress)
Dim lCell As Range: Set lCell = .Resize(sws.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If lCell Is Nothing Then Exit Sub
srCount = lCell.Row - .Row + 1
Set srg = .Resize(srCount)
End With
' Write the values from the source range to an array.
1
Dim Data As Variant
If srCount = 1 Then ' one cell
ReDim Data(1 To 1, 1 To 1): Data(1, 1) = srg.Value
Else ' multiple cells
Data = srg.Value
End If
' Write the unqiue values from the array to a dictionary.
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Dim Key As Variant
Dim r As Long
For r = 1 To srCount
Key = Data(r, 1)
If Not IsError(Key) Then
If Len(Key) > 0 Then
dict(Key) = Empty
End If
End If
Next r
If dict.Count = 0 Then Exit Sub
' Write the unqiue values from the dictionary to the array.
ReDim Data(1 To 2 * dict.Count - 1, 1 To 1)
r = -1
For Each Key In dict.Keys
r = r + 2
Data(r, 1) = Key
Next Key
' Write the unique values from the array to the destination range.
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
With dws.Range(dFirstCellAddress)
.Resize(r).Value = Data
.Resize(dws.Rows.Count - .Row - r + 1).Offset(r).Clear
'.EntireColumn = AutoFit
End With
'wb.Save
MsgBox "Uniques populated.", vbInformation
End Sub

Related

If 2 values from different sheets are equal, copy the rest of the row

I have 2 sheets with multiple rows and columns like this:
Sheet1:
I want to search each value from Sheet1, Column B in Sheet2, Column B then:
If the value is equal => Copy the rest of the row in sheet1.
At the end, sheet1 should look like this:
and Sheet2 the same, I don't modify in that, only I take from that the rest of the rows.
Thank you very much,
I have tried something like this:
Sub Compare()
Dim n As Integer
Dim sh As Worksheets
Dim r As Range
n = 1000
Dim match As Boolean
Dim valE As Double
Dim valI As Double
Dim I As Long, J As Long
For I = 2 To n
val1 = Worksheets("Sheet1").Range("B" & I).Value
val2 = Worksheets("Sheet2").Range("B" & I).Value
If val1 = val2 Then
Worksheets("Sheet1").Range("C" & I).Value = Worksheets("Sheet2").Range("C" & I)
Worksheets("Sheet1").Range("D" & I).Value = Worksheets("Sheet2").Range("D" & I)
Worksheets("Sheet1").Range("E" & I).Value = Worksheets("Sheet2").Range("E" & I)
I = I + 1
End If
Next I
Application.ScreenUpdating = True
End Sub
It works for 10 values or so, but I have 1200 values and it just doesn't do anything.
A VBA Lookup: Copy Rows
Type Wks
Name As String
LookupColumn As Long
FirstColumn As Long
End Type
Sub LookupData()
Dim Src As Wks
Src.Name = "Sheet2"
Src.LookupColumn = 2
Src.FirstColumn = 3
Dim Dst As Wks
Dst.Name = "Sheet1"
Dst.LookupColumn = 2
Dst.FirstColumn = 3
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Read source.
Dim sws As Worksheet: Set sws = wb.Worksheets(Src.Name)
Dim srg As Range, slData() As Variant, srCount As Long, cCount As Long
With sws.Range("A1").CurrentRegion
srCount = .Rows.Count - 1
cCount = .Columns.Count
If srCount = 0 Then Exit Sub
Set srg = .Resize(srCount).Offset(1)
End With
With srg.Columns(Src.LookupColumn)
If srCount = 1 Then
ReDim slData(1 To 1, 1 To 1): slData(1, 1) = .Value
Else
slData = .Value
End If
End With
Dim cOffset As Long: cOffset = Src.FirstColumn - 1
cCount = cCount - cOffset
Dim svData() As Variant
With srg.Resize(, cCount).Offset(, cOffset)
If srCount * cCount = 1 Then
ReDim svData(1 To 1, 1 To 1): svData = .Value
Else
svData = .Value
End If
End With
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Dim r As Long, cString As String
For r = 1 To srCount
cString = CStr(slData(r, 1))
If Not dict.Exists(cString) Then dict(cString) = r
Next r
' Read destination.
Dim dws As Worksheet: Set dws = wb.Worksheets(Dst.Name)
Dim drg As Range, dlData() As Variant, drCount As Long
With dws.Range("A1").CurrentRegion
drCount = .Rows.Count - 1
If drCount = 0 Then Exit Sub
Set drg = .Resize(drCount).Offset(1)
End With
With drg.Columns(Dst.LookupColumn)
If drCount = 1 Then
ReDim dlData(1 To 1, 1 To 1): dlData(1, 1) = .Value
Else
dlData = .Value
End If
End With
Dim dvData() As Variant: ReDim dvData(1 To drCount, 1 To cCount)
' Lookup and write to destination.
Dim dr As Long, c As Long
For r = 1 To drCount
cString = CStr(dlData(r, 1))
If dict.Exists(cString) Then
dr = dict(cString)
For c = 1 To cCount
dvData(r, c) = svData(dr, c)
Next c
End If
Next r
Dim dfCell As Range: Set dfCell = drg.Columns(Dst.FirstColumn).Cells(1)
Dim dvrg As Range: Set dvrg = dfCell.Resize(drCount, cCount)
dvrg.Value = dvData
' Inform.
MsgBox "Data copied.", vbInformation
End Sub

Find Matches in Column and Replace from External File

I use this VBA code which works very well. It searches in column A of an external Excel file for all the terms in column D, and replaces the matches, with the content of column B of the external file in the found row. So for instance:
if D5 matches A11 of the external file, then B11 from external file is written to D5.
I am now trying to modify it so that it still searches in column 4 for matches in column A of external file, but for any matches found, replaces the column E with column B of the external file. So:
If D5 matches A11, then B11 from external file is written to E5.
Well, I've tried many changes in the replace loop but it throws errors every time. I suppose I don't use the correct command!
Private Sub CommandButton1_Click()
Dim NameListWB As Workbook, thisWb As Workbook
Dim NameListWS As Worksheet, thisWs As Worksheet
Dim i As Long, lRow As Long
'This is the workbook from where code runs
Set thisWb = ThisWorkbook
Set thisWs = thisWb.Sheets("Sheet1")
'External file
Set NameListWB = Workbooks.Open("E:\Data.xlsx")
Set NameListWS = NameListWB.Worksheets("Sheet1")
With NameListWS
'Detect end row in Col A of Data.xlsx
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'Loop though Column A
For i = 1 To lRow
'... and perform replace action
thisWs.Columns(4).Replace What:=.Range("A" & i).Value, _
Replacement:=.Range("B" & i).Value, _
SearchOrder:=xlByColumns, _
MatchCase:=False
Next i
End With
End Sub ```
Untested:
Private Sub CommandButton1_Click()
Dim NameListWB As Workbook
Dim NameListWS As Worksheet, thisWs As Worksheet, n As Long
Dim i As Long, arrList, arrD, rngD As Range
Set thisWs = ThisWorkbook.Sheets("Sheet1") 'This is the workbook from where code runs
'get an array from the column to be searched
Set rngD = thisWs.Range("D1:D" & thisWs.Cells(Rows.Count, "D").End(xlUp).Row)
arrD = rngD.Value
'Open external file and get the terms and replacements as an array
Set NameListWB = Workbooks.Open("E:\Data.xlsx")
With NameListWB.Worksheets("Sheet1")
arrList = .Range("A1:B" & .Cells(Rows.Count, "A").End(xlUp).Row).Value
End With
For n = 1 To UBound(arrD, 1) 'check each value from ColD
For i = 1 To UBound(arrList, 1) 'loop over the array of terms to search for
If arrD(n, 1) = arrList(i, 1) Then 'exact match ?
'If InStr(1, arrD(n, 1), arr(i, 1)) > 0 Then 'partial match ?
rngD.Cells(n).Offset(0, 1).Value = arrList(i, 2) 'populate value from ColB into ColE
Exit For 'got a match so stop searching
End If
Next i
Next n
End Sub
A VBA Lookup (Application.Match)
Adjust (play with) the values in the constants section.
Compact
Sub VBALookup()
' Source
Const sPath As String = "E:\Data.xlsx"
Const sName As String = "Sheet1"
Const slCol As String = "A" ' lookup
Const svCol As String = "B" ' value
Const sfRow As Long = 2
' Destination
Const dName As String = "Sheet1"
Const dlCol As String = "D" ' lookup
Const dvCol As String = "E" ' value
Const dfRow As Long = 2
Application.ScreenUpdating = False
' Source
Dim swb As Workbook: Set swb = Workbooks.Open(sPath)
Dim sws As Worksheet: Set sws = swb.Worksheets(sName)
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, slCol).End(xlUp).Row
If slRow < sfRow Then Exit Sub ' no data in lookup column range
Dim srCount As Long: srCount = slRow - sfRow + 1
Dim slrg As Range: Set slrg = sws.Cells(sfRow, slCol).Resize(srCount)
Dim svData As Variant
With slrg.EntireRow.Columns(svCol)
If srCount = 1 Then ' one cell
ReDim svData(1 To 1, 1 To 1): svData(1, 1) = .Value
Else ' multiple cells
svData = .Value
End If
End With
' Destination
Dim dwb As Workbook: Set dwb = ThisWorkbook ' workbook containing this code
Dim dws As Worksheet: Set dws = dwb.Worksheets(dName)
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, dlCol).End(xlUp).Row
If dlRow < dfRow Then Exit Sub ' no data in lookup column range
Dim drCount As Long: drCount = dlRow - dfRow + 1
Dim dlrg As Range: Set dlrg = dws.Cells(dfRow, dlCol).Resize(drCount)
Dim dData As Variant
If drCount = 1 Then ' one cell
ReDim dData(1 To 1, 1 To 1): dData(1, 1) = dlrg.Value
Else ' multiple cells
dData = dlrg.Value
End If
' Loop.
Dim srIndex As Variant
Dim dValue As Variant
Dim dr As Long
Dim MatchFound As Boolean
For dr = 1 To drCount
dValue = dData(dr, 1)
If Not IsError(dValue) Then
If Len(dValue) > 0 Then
srIndex = Application.Match(dValue, slrg, 0)
If IsNumeric(srIndex) Then MatchFound = True
End If
End If
If MatchFound Then
dData(dr, 1) = svData(srIndex, 1)
MatchFound = False
Else
dData(dr, 1) = Empty
End If
Next dr
' Close the source workbook.
swb.Close SaveChanges:=False
' Write result.
dlrg.EntireRow.Columns(dvCol).Value = dData
' Inform.
Application.ScreenUpdating = True
MsgBox "VBA lookup has finished.", vbInformation
End Sub

Look for a cell value (more than one instance) in a column then copy corresponding row values to another row (against other cell value)

I want to look for value of Forecast in cell (F column) (more than one instance - unique key is Prod and Cust), then copy corresponding row values to other rows identified by Edited Forecast value in another cell (more than one instance - unique key is Prod and Cust (same column).)
This is only copying Row values.
Private AutomationObject As Object
Sub Save ()
Dim Worksheet as Worksheet
Set Worksheet = ActiveWorkbook.Worksheets("Sheet")
Worksheet.Range("M18:AX18").Value = Worksheet.Range("M15:AX15").Value
End Sub
Fill Blanks (Unique Dictionary)
Option Explicit
Sub FillBlanks()
Const sFirstCellAddress As String = "D3"
Const sDelimiter As String = "#"
Const dCols As String = "I:K"
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
Dim srg As Range
Dim rCount As Long
With ws.Range(sFirstCellAddress)
Dim lCell As Range: Set lCell = .Resize(ws.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If lCell Is Nothing Then Exit Sub
rCount = lCell.Row - .Row + 1
Set srg = .Resize(rCount, 2)
End With
Dim sData As Variant: sData = srg.Value
Dim drg As Range: Set drg = srg.EntireRow.Columns(dCols)
Dim dcCount As Long: dcCount = drg.Columns.Count
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Dim rg As Range
Dim r As Long
Dim sString As String
For r = 1 To rCount
sString = sData(r, 1) & sDelimiter & sData(r, 2)
If Application.CountBlank(drg.Rows(r)) = dcCount Then
If dict.Exists(sString) Then
If IsArray(dict(sString)) Then
drg.Rows(r).Value = dict(sString)
Else
dict(sString).Add drg.Rows(r)
End If
Else
Set dict(sString) = New Collection
dict(sString).Add drg.Rows(r)
End If
Else
If dict.Exists(sString) Then
If IsArray(dict(sString)) Then
'drg.Rows(r).Value = dict(sString) ' overwrite!?
Else
For Each rg In dict(sString)
rg.Value = drg.Rows(r).Value
Next rg
dict(sString) = drg.Rows(r).Value
End If
Else
dict(sString) = drg.Rows(r).Value
End If
End If
Next r
MsgBox "Data updated.", vbInformation
End Sub

Copy every second value of a row and paste into a column in another sheet

pls help, I need a excel vba code, which copies every second value of a row
and paste that into a column in another sheet
.
I tried it like this
Sub Test()
Worksheets("Sheet1").Activate
Dim x As Integer
For x = 5 To 196 Step 2
Worksheets("Tabelle1").Activate
Cells(x, 2).Value = Sheets("Sheets1").Range("E2:GN2")
Next x
End Sub
Sub test()
Dim WkSource As Worksheet
Dim WkDestiny As Worksheet
Dim i As Long
Dim j As Long
Dim LR As Long
Dim k As Long
Set WkSource = ThisWorkbook.Worksheets("Hoja1")
Set WkDestiny = ThisWorkbook.Worksheets("Hoja2")
With WkSource
LR = .Range("E" & .Rows.Count).End(xlUp).Row
k = 2 'starting row where you want to paste data in destiny sheet
For i = 2 To LR Step 1
For j = 5 To 12 Step 2 'j=5 to 12 because my data goes from column E to L (5 to 12)
WkDestiny.Range("D" & k).Value = .Cells(i, j).Value
k = k + 1
Next j
Next i
End With
Set WkSource = Nothing
Set WkDestiny = Nothing
End Sub
The code loop trough each row and each column (notice step 2 to skip columns)
Output I get:
you can start from something like this:
Option Explicit
Private Sub dataCp()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Sheets("Sheet1")
Dim ws2 As Worksheet: Set ws2 = wb.Sheets("Tabelle1")
Dim lrow As Long, lcol As Long, i As Long
Dim rng As Range, c As Range
lcol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
For i = 5 To lcol
lrow = (ws2.Cells(ws2.Rows.Count, "D").End(xlUp).Row) + 1
ws2.Range("D" & lrow).Value = ws.Cells(2, i).Value
i = i + 1
Next
End Sub
Transpose Data
It will transpose all rows of a range in a worksheet to consecutive columns on another worksheet.
Since scStep is 2, in this case, only every other cell in each source row will be copied.
Adjust (play with) the values in the constants section.
Option Explicit
Sub TransposeData()
' Source
Const sName As String = "Sheet1"
Const sFirstRowAddress As String = "E2:GN2"
Const scStep As Long = 2
' Destination
Const dName As String = "Tabelle1"
Const dFirstCellAddress As String = "D2"
' Both
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Write the values from the source range to the source array.
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim sData As Variant
Dim srCount As Long
With sws.Range(sFirstRowAddress)
' Populate data.
' With .Resize(20)
' .Formula = "=RANDBETWEEN(1,100)"
' .Value = .Value
' End With
Dim lCell As Range: Set lCell = .Resize(sws.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If lCell Is Nothing Then Exit Sub ' no data in data range
srCount = lCell.Row - .Row + 1
sData = .Resize(srCount).Value
End With
' Define the destination array.
Dim scCount As Long: scCount = UBound(sData, 2)
Dim drCount As Long
drCount = Int(scCount / scStep) - CLng(scCount Mod scStep > 0)
Dim dData As Variant: ReDim dData(1 To drCount, 1 To srCount)
' Write the data from the source array to the destination array.
Dim r As Long, c As Long
For c = 1 To srCount
For r = 1 To drCount
dData(r, c) = sData(c, (r - 1) * scStep + 1)
Next r
Next c
' Write the values from the destination array to the destination range.
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
With dws.Range(dFirstCellAddress).Resize(, srCount) ' first row range
' Write data.
.Resize(drCount).Value = dData
' Clear below.
.Resize(dws.Rows.Count - .Row - drCount + 1).Offset(drCount).Clear
' Apply some formatting.
'.EntireColumn.AutoFit
End With
' Inform.
MsgBox "Data transposed.", vbInformation
End Sub

Remove duplicates from range not removing anything

The following code does not remove any duplicate, what am I missing ?
LastColumn = 10
ws.Range(ws.Cells(1, ws.Range("AY1").Column + LastColumn - 1).Address(), ws.Cells(1, "AY").Address()).RemoveDuplicates
I replaced RemoveDuplicates by .Select to check if the excepted range was selected and it was.
Please, test the next way. It will keep only the first occurrences and replace with empty cells the next duplicates. The processed result is returned on the next (second) row (for testing reason). If it works as you need, you can simple replace ws.Range("AY2").Resize with ws.Range("AY1").Resize:
Sub removeDuplicatesOnRow()
Dim ws As Worksheet, lastColumn As Long, arrCol, i As Long
lastColumn = 10
Set ws = ActiveSheet
arrCol = ws.Range(ws.cells(1, ws.Range("AY1").Column + lastColumn - 1), ws.cells(1, "AY")).value
arrCol = removeDuplKeepEmpty(arrCol)
ws.Range("AY2").Resize(1, UBound(arrCol, 2)).value = arrCol
End Sub
Function removeDuplKeepEmpty(arr) As Variant
Dim ar, dict As Object, i As Long
ReDim ar(1 To 1, 1 To UBound(arr, 2))
Set dict = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(arr, 2)
If Not dict.Exists(arr(1, i)) Then
dict(arr(1, i)) = 1
ar(1, i) = arr(1, i)
Else
ar(1, i) = ""
End If
Next i
removeDuplKeepEmpty = ar
End Function
If you need to keep only unique values/strings in consecutive columns, the function can be adapted to do it. You did not answer my clarification question on the issue and I assumed that you do not want ruining the columns below the processed row. But, if my supposition is wrong, I can post a code doing the other way...
Remove Row Duplicates
Option Explicit
Sub RemoveRowDuplicates()
Dim ws As Worksheet: Set ws = ActiveSheet ' be more specific
Dim fCell As Range: Set fCell = ws.Range("AY1")
Dim lCell As Range: Set lCell = ws.Cells(1, ws.Columns.Count).End(xlToLeft)
If lCell.Column < fCell.Column Then Exit Sub ' no data in row range
Dim rg As Range: Set rg = ws.Range(fCell, lCell)
Dim cCount As Long: cCount = rg.Columns.Count
If cCount < 2 Then Exit Sub ' only one column
Dim sData As Variant: sData = rg.Value ' Source
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare ' ignore case i.e. 'A = a'
Dim dData As Variant: ReDim dData(1 To 1, 1 To cCount) ' Dest. (Result)
Dim sValue As Variant
Dim sc As Long
Dim dc As Long
For sc = 1 To cCount
sValue = sData(1, sc)
If Not IsError(sValue) Then ' is not an error value
If Len(sValue) > 0 Then ' is not blank
If Not dict.Exists(sValue) Then ' not found in dictionary
dict(sValue) = Empty
dc = dc + 1
dData(1, dc) = sValue
'Else ' found in dictionary
End If
'Else ' is blank
End If
'Else ' is error value
End If
Next sc
rg.Value = dData
MsgBox "Found " & dc & " unique values.", vbInformation
End Sub

Resources