Selecting elements from one column missing in another column, with VBA - vba

I have two columns, A and B, and I need to find every element on column B that is not on column A, and paste them in a third column, C.
For example:
A B
23 5
1 4
5 7
4 23
1
Then:
C
7
Searching for solutions, people usually suggest VLOOKUP() for similar problems. However, I need something with VBA, because each of these columns is in a different Workbook.
What is a good way to do this comparison?
Thank you

Using loops in Vba
counter = 0
k = 2
For i = 2 To lastrowA
For j = 2 To lastRowB
If Sheet1.Cells(i, "A") = Sheet1.Cells(j, "B") Then
counter = 1
End If
Next j
If counter = 0 Then
Sheet1.Cells(k, "C") = Sheet1.Cells(j, "B")
k = k + 1
End If
counter = 0
Next i

You can use VLookup in VBA. Here is the syntax:
Application.WorksheetFunction.VLOOKUP(lookup_value, table_array, column_index, range_lookup)
Otherwise you could do loops
For each elementB in columnB
For each elementA in columnA
If elmentA <> ElementB then
---Save ElementA in an Array
End if
next elementB
next elementA

Related

Shuffle an existing column multiple times with no repeats on any row

I am using VBA
I have a column of integers in an array
I run the array thru a randomizer module and copy that to a second column
I run the array thru a randomizer module and copy that to a third column
I run the array thru a randomizer module and copy that to a fourth column
The issue I can't seem to over come is duplicates on the same row
IE:
2 13 27 14
27 27 13 5
14 5 2 13
13 2 14 27
5 14 5 2
*columns are much longer
I have searched the web but everyone is focused on creating random numbers without duplicate. I have found shuffling but once again it seems to be one dimensional.
'// get a random number from 1 to the last row of column 25
For N1 = 1 To LastRow
Again:
Randomize Timer
RNum = Int(Rnd * (LastRow - 1 + 1) + 1)
'// this is where the values in "NArray" get shuffled around
Temp = NArray(N1)
NArray(N1) = NArray(RNum)
NArray(RNum) = Temp
ws5.Cells(N1, Lp) = NArray(N1)
'// this looks for duplicate numbers in the row
Select Case Lp
Case 26: a = ws5.Cells(N1, Lp).Value + 0
b = ws5.Cells(N1, Lp - 1).Value + 0
If a = b Then
GoTo Again
End If
Case 27: a = ws5.Cells(N1, Lp).Value + 0
b = ws5.Cells(N1, Lp - 2).Value + 0
c = ws5.Cells(N1, Lp - 1).Value + 0
If a = b Then
GoTo Again
ElseIf a = c Then
GoTo Again
End If
...
'// the shuffled array is inserted into the cells of column 26
For N1 = 1 To LastRow
ws5.Cells(N1, Lp) = NArray(N1)
Next N1
Next Lp
no errors with the exception that when comparing cell values in the row going from column to column it misses duplicate values such as row 2 column 3 may contain "14" and row 2 column 4 contains "14" it doesn't loop back and get another value for column 4

VBA numbering loop

I am trying to simplify a code in a Macro for numbering rows of specific columns of excel. Currently I am using
With Sheet1.Range("V6")
.Value = 1
.AutoFill .Resize(V6 + C, 1), xlFillSeries
End With
The macro has already set "C" as a variable that can change each time it is run. I want to simplify the code because I don't know how to loop this to repeat in every third column. I have tried For Loops but i am new to VBA and cannot get the program to run. Looping this would help me becasue I currently have this same code altered 85 differnt times to fill 85 different columns. For example, the next set is
With Sheet1.Range("Y6")
.Value = 1
.AutoFill .Resize(Y6 + C, 1), xlFillSeries
End With
Is there a more simple way this can be accomplished?
An alternate approach using Offset to fill every third column, starting in V6.
Sub MyNumbering()
Dim c As Long, i As Long
c = 100
For i = 0 To 84
With Sheet1.Range("V6").Offset(, i * 3)
.Value = 1
.AutoFill .Resize(c), xlFillSeries
End With
Next i
End Sub
This will iterate every 3rd column starting with column V and post 85 columns of row numbers starting in row 6 and ending at C + 6
Sub mynum()
Dim c As Long: c = 100
Dim j As Long
For j = 22 To 22 + 85 * 3 Step 3
With Sheet1.Range(Sheet1.Cells(6, j), Sheet1.Cells(c + 6, j))
.Formula = "=ROW(1:1)"
.Value = .Value
End With
Next j
End Sub

Use VBA to place matching values in one column next to their match in another column

I would like to take values from column A and cut and paste them into column B, with each value exactly one cell to the left of their corresponding matching values from column C. Here is a before and after of what I would like to accomplish. Basically, each value from column A finds its match in column C and is copied, then pasted directly to the left of its match in column B.
Column A Column C
10 1
9 2
8 3
7 4
6 5
5 6
4 7
3 8
2 9
1 10
Column B Column C
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
Here it what I have tried:
Sub arrange()
Cells(1, 1).Activate
Do
If IsEmpty(ActiveCell) Then Exit Do
If ActiveCell.Offset(0, 2).Value = ActiveCell.Value Then
ActiveCell.Select
Selection.Copy
ActiveCell.Offset(0, 1).Select
ActiveSheet.Paste
ActiveCell.Offset(1, -1).Activate
Else
ActiveCell.Offset(1, 0).Activate
End If
Loop
End Sub
The problem with this approach is that it only finds matching values in the same row. I want it to be able to search the entire column and place the value next to a match, whether the match is in the same row or not.
What you need to do is loop through column A and check to see if each value can be found in column C. If it is copy to column B.
Sub arrange()
Dim Wbk As Workbook
Set Wbk = ActiveWorkbook
Dim row As Integer
Dim col As Integer
Dim currentA As Integer
Dim numRows As Integer
Worksheets("chicoexcel").Activate
numRows = Wbk.Worksheets("chicoexcel").Range("A2", Range("A2").End(xlDown)).Rows.Count
For a = 1 To numRows + 1 'start at 1 because it is the first row. This will loop through Column A
currentA = Sheets("chicoexcel").Cells(a, "A").Value 'Save the current value in column A
For c = 1 To numRows + 1 'start at 1 because it is the first row. This will loop through Column C
If (Sheets("chicoexcel").Cells(c, "C").Value = currentA) Then 'Check if the col C value is equal to the current col A value.
Sheets("chicoexcel").Cells(c, "B") = Sheets("chicoexcel").Cells(c, "C").Value 'If so copy to column B
Sheets("chicoexcel").Cells(a, "A") = Null 'Remove the value from col A
End If
Next c
Next a
End Sub
I assumed all the values were integers, and that the data starts in row 1.
This is not the most efficient solution, but you'll be able to see what is happening using the debugger. You could include the FIND function to speed things up. I'll let you figure that out yourself.

Generate table by VBA in Excel

I'm new in VBA. I hope that this is not a difficult question for you.My problem:
I have TEXT in column A and NUMBER in column B. Like this:
Column A Column B
TEXT 1 3
TEXT 2 2
TEXT 3 3
..... ...
I need to auto-generate a table in other sheet which has two columns. First contains the text which repeats n times (NUMBER in column B) and then the next text from Column A. In the second column of this table I need number from 1 to NUMBER. like this:
Column A Column B
TEXT 1 1
TEXT 1 2
TEXT 1 3
TEXT 2 1
TEXT 2 2
TEXT 3 1
TEXT 3 2
TEXT 3 3
.... ....
Then I have to post-process this table, but I know how to make it. I don't know how to generate the table.
Expanding on my comment:
Sub MakeTable()
Dim i As Long, j As Long, k As Long, m As Long, n As Long
Dim t As String
Dim ws As Worksheet
Sheets(1).Activate
Set ws = Sheets(2)
n = Cells(Rows.Count, 1).End(xlUp).Row()
k = 1
For i = 1 To n
t = Cells(i, 1).Value
m = Cells(i, 2).Value
For j = 1 To m
ws.Cells(k, 1).Value = t
ws.Cells(k, 2).Value = j
k = k + 1
Next j
Next i
End Sub
This assumes that the original data is in Sheet1 and you are transferring it to Sheet2, and that the data begins in row 1. Adjust accordingly if those assumptions are false. The way I determine the last cell in column A that has data is an important idiom in Excel VBA and should be mastered.

Excel: Reference non-zero cells

I'm trying to list 50 rows x 8 columns of cells (defined 'allhazards') into one column
However each cell in myhazards is referencing other sheets and contain 0's where there is no text to be referenced.
When I list the data in 'allhazards' in a single column using this formula:
=INDEX(allhazards,1+INT((ROW($A1)-1)/COLUMNS(allhazards)),MOD(ROW($A1)-1+COLUMNS(allhazards),COLUMNS(allhazards))+1)
(then drag down the column to get all of the cells from 'allhazards')
How do I implement this:
if cell in 'allhazards' is 0, do not reference this cell, move to next row
...then reference next row's columns until cell is 0, then move to next row
...keep doing this until there are no rows left to be referenced
eg. if 'allhazards' contained these cells (eg. 2 rows x 8 columns):
hello how are 0 0 0 0 0
good 0 0 0 0 0 0 0
It should produce this when dragging down the formula:
hello
how
are
good
but not this:
hello
how
are
0
0
0
0
0
good
0
0
0
0
0
0
0
I created a UDF for your situation. Please place the following procedure in a standard code module.
Public Function MATRIX2VECTOR(r As Range)
Dim i&, j&, k&, v, m, o
v = r
ReDim o(1 To Application.Caller.Rows.Count, 1 To 1)
For i = 1 To UBound(v, 1)
For j = 1 To UBound(v, 2)
m = v(i, j)
If Len(m) Then
If m <> 0 Then
k = k + 1
o(k, 1) = v(i, j)
End If
End If
Next
Next
For k = k + 1 To UBound(o): o(k, 1) = "": Next
MATRIX2VECTOR = o
End Function
Now you can call it in a formula from the worksheet just like any of the built-in functions.
1
Select a vertical range of cells tall enough to accommodate the transposed data.
2
Click in the Formula Bar at the top of Excel.
3
Enter this formula:
=MATRIX2VECTOR(allhazards)
4
This is an array formula and must be confirmed with Ctrl+Shift+Enter.
If you're interested in a non-VBA solution:
=IF(ROWS($1:1)>COUNTIF(allhazards,"<>0"),"",INDIRECT(TEXT(AGGREGATE(15,6,(10^5*ROW(allhazards)+COLUMN(allhazards))/(allhazards<>0),ROWS($1:1)),"R0C00000"),0))
Copy down as required.
This will be more efficient if you use a single helper cell to store the number of non-zero entries in allhazards, and also store the ROW/COLUMN portion as a Defined Name. For example, if you put:
=COUNTIF(allhazards,"<>0")
in e.g. J1, and define, in Name Manager, Arry1 as:
=10^5*ROW(allhazards)+COLUMN(allhazards)
then the main formula becomes:
=IF(ROWS($1:1)>$J$1,"",INDIRECT(TEXT(AGGREGATE(15,6,Arry1/(allhazards<>0),ROWS($1:1)),"R0C00000"),0))
If your data is in a different sheet to that housing the results, simply include the sheet name containing the data, viz:
=IF(ROWS($1:1)>$J$1,"",INDIRECT("'YourSheetName'!"&TEXT(AGGREGATE(15,6,Arry1/(allhazards<>0),ROWS($1:1)),"R0C00000"),0))
Regards