Not sure how to put this in words, but basically macro is run from the sheet1 of WorkBook1, and it should produce one like sheet1 of WorkBook2. (WB2 Sheet1 is empty)
The trick is that macro should only work with user selected range.
So if A1:A7 is selected, it will only grab data from A1:A7 to last column with data
If nothing is selected then exit sub with msgbox or something
Order/sort does not matter as long as it merges XYs duplicates and group respective fruits together.
A B => A B C
1 XY3 Apple => 1 H XY1
2 XY1 Orange => 2 D Orange
3 XY3 Banana => 3 H XY2
4 XY3 Banana => 4 D Orange
5 XY3 Peach => 5 H XY3
6 XY4 Orange => 6 D Apple
7 XY2 Orange => 7 D Banana
8 XY7 Apple => 8 D Banana
=> 9 D Peach
=> 10 H XY4
=> 11 D Orange
[WB1 Sheet1] => [WB2 Sheet1]
This might be difficult but I am desperately seeking for help.
Thank you so much!
I set up this macro to copy to sheet2 of the same workbook. To save to a new workbook just update the following line of code with your workbook name instead of activeworkbook.
Set sheetB = ActiveWorkbook.Sheets("Sheet2")
Started with the following data in sheet 1 and a blank sheet 2:
Select A1 to A8 and run this macro:
Sub CopyAndFormat()
If IsEmpty(Selection) Then
MsgBox ("Empty Cell")
Exit Sub
End If
Dim sheet As Worksheet
Set sheetA = ActiveWorkbook.Sheets("Sheet1")
Set sheetB = ActiveWorkbook.Sheets("Sheet2")
Dim FirstRow As Long, LastRow As Long
FirstRow = Selection.Rows(1).Row
LastRow = Selection.Rows.Count + FirstRow - 1
'First Column
Dim rngA As Range
Set rngA = Range("A" & FirstRow & ":A" & LastRow)
Dim datA As Variant
datA = rngA
Dim i As Long
'Second Column Match
Dim rngB As Range
Set rngB = Range("B" & FirstRow & ":B" & LastRow)
Dim datB As Variant
datB = rngB
Dim j As Long
Dim resultA As Variant
Dim resultB As Variant
Dim rng As Range
Dim rngr As Range
Set rng = sheetB.Range("A1:A" & LastRow + 100)
Set rngr = sheetB.Range("B1:B" & LastRow + 100)
resultA = rng
resultB = rngr
'Store duplicates
Dim rngString As String
rngString = "empty"
Dim match As Boolean
match = False
Dim cntr As Integer
cntr = 1
'First Column loop
For i = LBound(datA, 1) To UBound(datA, 1)
If rngString <> "empty" Then
If Not Intersect(Range("A" & i), Range(rngString)) Is Nothing Then
GoTo nextloop
End If
End If
'Second Column Loop
For j = LBound(datA, 1) + i To UBound(datA, 1)
If i <> j And datA(i, 1) = datA(j, 1) And Not IsEmpty(datA(j, 1)) And Not IsEmpty(datA(i, 1)) Then
'copy position of duplicate in variant
If rngString = "empty" Then
match = True
resultA(cntr, 1) = datA(i, 1)
resultB(cntr + 1, 1) = datB(i, 1)
resultB(cntr + 1, 1) = datB(i, 1)
resultB(cntr + 2, 1) = datB(j, 1)
rngString = "A" & i & ",A" & j
cntr = cntr + 2
Else
resultB(cntr + 1, 1) = datB(j, 1)
cntr = cntr + 1
rngString = rngString & "," & "A" & j
End If
End If
Next
If match = False Then
resultA(cntr + 1, 1) = datA(i, 1)
resultB(cntr + 2, 1) = datB(i, 1)
cntr = cntr + 2
End If
match = False
'cntr = cntr + 1
nextloop:
Next
rng = resultA
rngr = resultB
End Sub
You'll get the following on sheet2:
Sorry the code is a little messy and I hate using goto's but this will get you started.
Related
I have to create a Macro which lets me Concatenate two columns at a time in a given range. For example: In range C1:Z200, I want to concatenate Column C&D, E&F, G&H and so on. How do I do it. This is my current code which only concatenate first two columns..rest remains the same.
Set Range = ActiveSheet.Range("C1:Z100")
For Each c In Range
c.Select
ActiveCell.FormulaR1C1 = ActiveCell & " " & ActiveCell.Offset(0, 1)
ActiveCell.Offset(0, 1).Activate
Selection.Clear
ActiveCell.Offset(0, 2).Activate
Next c
Try this:
Sub Concat()
Dim i As Long, j As Long
For i = 1 To 100 'number of rows
j = 1 'reset column to 1
Do While j < 25 'max number of columns (until Column Y-Z)
j = j + 2 'start from third column (Column C)
Cells(i, j) = Cells(i, j) & " " & Cells(i, j + 1) 'concat
Cells(i, j + 1).ClearContents 'clear
Loop
Next i 'next row
End Sub
Try this:
Sub ConcatAltCellsInAltCols()
Dim oW As Worksheet: Set oW = ThisWorkbook.Worksheets("Sheet11")
Dim iLC As Long: iLC = oW.Cells(1, oW.Columns.Count).End(xlToLeft).Column
Dim iLR As Long: iLR = oW.Cells(oW.Rows.Count, 3).End(xlUp).Row
Dim iC As Long
Dim iR As Long
For iR = 1 To iLR
For iC = 3 To iLC Step 2
oW.Cells(iR, iC).Value = oW.Cells(iR, iC) & oW.Cells(iR, iC + 1)
Next
Next
End Sub
Try this using a one based array for better Performance:
Code
Option Explicit
Sub Conc()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Concat") ' <== change "Concat" to your sheet name to avoid subscript error
Dim v ' variant
Dim lng As Long
Dim j As Integer ' corr.
' use one based array to get field data
v = ws.Range("C1:Z100") ' your OP range
For lng = 1 To UBound(v)
' concatenate columns C&D, E&F, G&H, ...
For j = 0 To 11
v(lng, j * 2 + 1) = v(lng, j * 2 + 1) & v(lng, j * 2 + 2)
Next j
Next lng
' write array values back (overwriting D, F, H,... with the same values)
ws.Range("C1:Z100") = v ' your OP range
End Sub
I am using the code below and it works for filtering the unique name and totalting the value field. I recently have a need to expand upon the filtering of unique names to include other columns in the criteria. Please see the example output I am looking for. Any help would be appreciated.
Sub SUM()
Dim i, j, k As Integer
i = 2
j = 2
Range("D1").Value = "NAME"
Range("E1").Value = "VALUE"
'copy the first value of column A to column D
Range("D2").Value = Range("A2").Value
'cycle to read all values of column B and sum it to column E; will run until find a blank cell
While Range("A" & i).Value <> ""
'this check if actual value of column A is equal to before value of column A, if true just add the column B value to E
'else, look for the row in column D where is the same value of column A, if it doesn't exist code create the value
'in column D and E
If Range("A" & i).Value = Range("A" & i - 1).Value Then
Range("E" & j).Value = Range("E" & j).Value + Range("B" & i).Value
Else
flag = 1
While Range("D" & flag).Value <> ""
If Range("A" & i).Value = Range("D" & flag).Value Then
j = flag
Range("E" & j).Value = Range("E" & j).Value + Range("B" & i).Value
flag = Range("D1").End(xlDown).Row
Else
j = 0
End If
flag = flag + 1
Wend
If j = 0 Then
Range("D1").End(xlDown).Offset(1, 0).Value = Range("A" & i).Value
Range("E1").End(xlDown).Offset(1, 0).Value = Range("B" & i).Value
j = Range("E1").End(xlDown).Row
End If
End If
i = i + 1
Wend
MsgBox "End"
End Sub
Currently outputs like this:
Name Value Name Sum
A 1 A 13
A 2 B 7
B 1 C 3
B 3
C 2
A 1
B 2
A 3
B 1
A 2
A 4
C 1
I would like to have it export data like this example:
Name Code Date Value Name Code Date Sum
A 101 3/10/17 1 A 101 3/10/17 9
A 101 3/10/17 2 A 102 3/10/17 4
B 102 3/10/17 1 B 101 3/10/17 3
B 101 3/10/17 3 B 102 3/10/17 2
C 102 3/8/17 2 B 101 3/8/17 2
A 102 3/10/17 1 C 102 3/8/17 2
B 101 3/8/17 2 C 102 3/10/17 1
A 102 3/10/17 3
B 102 3/10/17 1
A 101 3/10/17 2
A 101 3/10/17 4
C 102 3/10/17 1
As long as your columns go A,B,C,D then F,G,H,I then below code should work. Let me know if it works for you.
Sub CountCodes()
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
Dim wbk As Workbook
Dim ws As Worksheet
Dim wsRow As Long, newRow As Long
Dim Names() As String
Dim Found As Boolean
Dim x As Integer, y As Integer, z As Integer, myCount As Integer, mySum As Integer
Dim Cell As Range
Set wbk = ThisWorkbook
Set ws = wbk.Worksheets(1)
ReDim Names(0 To 0) As String
ReDim Codes(0 To 0) As String
ReDim Dates(0 To 0) As String
newRow = 1
With ws
'Find last row of data
wsRow = .Range("A" & .Rows.Count).End(xlUp).Row
'Loop through Column A to fill array
For Each Cell In .Range(.Cells(2, 1), .Cells(wsRow, 1))
'Fill Names array
Found = (IsInArray(Cell.Value2, Names) > -1)
If Found = False Then
Names(UBound(Names)) = Cell.Value2
If Cell.Row <> wsRow Then
ReDim Preserve Names(0 To UBound(Names) + 1) As String
End If
End If
'Fill Codes array
Found = (IsInArray(Cell.Offset(0, 1).Value2, Codes) > -1)
If Found = False Then
Codes(UBound(Codes)) = Cell.Offset(0, 1).Value2
If Cell.Row <> wsRow Then
ReDim Preserve Codes(0 To UBound(Codes) + 1) As String
End If
End If
'Fill Dates array
Found = (IsInArray(Cell.Offset(0, 2).Value2, Codes) > -1)
If Found = False Then
Dates(UBound(Dates)) = Cell.Offset(0, 2).Value
If Cell.Row <> wsRow Then
ReDim Preserve Codes(0 To UBound(Dates) + 1) As String
End If
End If
Next
'Add Autofilter if off
If .AutoFilterMode = False Then
.Range("A1").AutoFilter
End If
For x = LBound(Names) To UBound(Names)
.Range("A1").AutoFilter Field:=1, Criteria1:=Names(x)
For y = LBound(Codes) To UBound(Codes)
.Range("B1").AutoFilter Field:=2, Criteria1:=Codes(y)
For z = LBound(Dates) To UBound(Dates)
.Range("C1").AutoFilter Field:=3, Criteria1:=Dates(z)
For Each Cell In .Range("A1:A" & wsRow).SpecialCells(xlCellTypeVisible)
myCount = myCount + 1
Next
If myCount > 1 Then
For Each Cell In .Range("D2:D" & wsRow).SpecialCells(xlCellTypeVisible)
mySum = mySum + Cell.Value2
Next
'Find last row in new data
newRow = newRow + 1
.Cells(newRow, 6) = Names(x)
.Cells(newRow, 7) = Codes(y)
.Cells(newRow, 8) = Dates(z)
.Cells(newRow, 9) = mySum
End If
myCount = 0
mySum = 0
Next z
Next y
Next x
.ShowAllData
End With
Erase Names
Erase Codes
Erase Dates
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Long
'http://stackoverflow.com/questions/10951687/how-to-search-for-string-in-an-array
'Boolean = (IsInArray(StringToFind, ArrayToSearch) > -1)
Dim i As Long
' default return value if value not found in array
IsInArray = -1
For i = LBound(arr) To UBound(arr)
If StrComp(stringToBeFound, arr(i), vbTextCompare) = 0 Then
IsInArray = i
Exit For
End If
Next i
End Function
I used a pivot table in Excel 2016 to generate this view, since you are not opposed to using a Pivot Table. If Excel can do this out of the box, and you are happy with how it looks and behaves, there is no real need for custom VBA in this case.
Just do the following:
Highlight your data, then insert > pivot table
I placed the pivot table in cell F1 of Sheet 1
Add Name, Code, and Date to the Rows of the pivot table
Add Value to the Values of the pivot table. It should default to Sum.
Click on the pivot table, then in the pivot table tools > design tab in the ribbon, go to the "Layout" ribbon group:
On the Report Layout Dropdown:
Click "Show in Tabular Form"
Click "Repeat All Item Labels"
On the Subtotals Dropdown:
Click "Do Not Show Subtotals"
On the Grand totals Dropdown:
Click "off for rows and columns"
You could use Dictionary object:
Option Explicit
Sub ListTotals()
Dim c As Range, dataRng As Range
Dim key As Variant
Set dataRng = Range("A2", Cells(Rows.Count, 1).End(xlUp))
With CreateObject("Scripting.Dictionary")
For Each c In dataRng
key = Join(c.Resize(,3), "|")
.Item(key) = .Item(key) + c.Offset(,4)
Next c
With dataRng.Resize(.Count)
.Offset(,5) = Application.Transpose(.Keys)
.Offset(,8) = Application.Transpose(.Items)
.Offset(,5).TextToColumns DataType:=xlDelimited, Other:=True, OtherChar:="|", FieldInfo:= Array(Array(1, 2), Array(3, 3))
End With
End With
End Sub
I have data in three columns, A, B and C.
I want to copy the following 3 values from column C if there is a match between column A and B. For example, I would like to copy number 1,3 and 6 from column C because A and B match in third row.
A B C
1 2 4
3 4 4
5 5 1
4 6 3
4 8 6
1 8 3
I have tried Resize, Range(Cells(Selection.Row, 1), Cells(Selection.Row, 3)).Copy etc. but nothing seem to work.
Sub test()
Dim rngsize As Range, rngsize2 As Range, rngmake As Range, rngmake2 As Range, rngprice As Range, rngprice2 as range, i As Integer, j As Integer, x As Integer
x = 3
For i = 2 To Sheets("Sheet3").Range("E" & Rows.Count).End(xlUp).Row
For j = 7 To Sheets("Sheet2").Range("E" & Rows.Count).End(xlUp).Row
Set rngsize = Sheets("Sheet3").Range("E" & i)
Set rngsize2 = Sheets("Sheet2").Range("E" & j)
Set rngmake = Sheets("Sheet3").Range("F" & i)
Set rngmake2 = Sheets("Sheet2").Range("F" & j)
Set rngprice = Sheets("Sheet3").Range("X" & i)
Set rngprice2 = Sheets("Sheet2").Range("X" & j)
If rngsize * 0.5 <= rngsize And rngsize2 + 1.5 >= rngsize Then
If rngmake2 * 0.5 <= rngmake And rngmake2 * 1.5 >= rngmake Then
Range(Cells(Selection.Row, 1), Cells(Selection.Row, 3)).Copy
rngprice2.Copy
Worksheets("Sheet4").Range("F" & x).PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = xlCopy
x = x + 1
End If
End If
Next j
Next i
End Sub
I could not follow your code so I threw something together based on your example and description. You will have to modify the constants and worksheets to fit your application.
From your description and example you want VBA for:
When A matches B in the same row, copy C from that row and C from the next 2 rows to another worksheet.
Private Sub CopyMatch()
Dim i As Integer
Dim j As Integer
Dim wsCopy As Worksheet
Dim wsPaste As Worksheet
Const intACol As Integer = 1
Const intBCol As Integer = 2
Const intCCol As Integer = 3
Const intPasteCol As Integer = 1
Const intCopyRowStart As Integer = 2
Const intPasteRowStart As Integer = 1
'assign worksheets
Set wsCopy = Sheets("Sheet1")
Set wsPaste = Sheets("Sheet2")
'cycle through each row
i = intCopyRowStart
j = intPasteRowStart
Do Until wsCopy.Cells(i, intACol).Value = "" And _
wsCopy.Cells(i, intBCol).Value = "" And _
wsCopy.Cells(i, intCCol).Value = ""
'check for A-B match
If wsCopy.Cells(i, intACol).Value = wsCopy.Cells(i, intBCol).Value Then
'copy C value from match row + 2 next rows for C
wsCopy.Range(Cells(i, intCCol), Cells(i + 2, intCCol)).Copy
'paste in other sheet
wsPaste.Cells(j, intPasteCol).PasteSpecial Paste:=xlPasteValues
j = j + 3
End If
i = i + 1
Loop
End Sub
This returned the values 1,3, & 6 in another sheet.
My attempt to apply this to your code is as follows:
Sub test()
Dim rngsize As Range, rngsize2 As Range, rngmake As Range, rngmake2 As Range, rngprice As Range, rngprice2 As Range, i As Integer, j As Integer, x As Integer
x = 3
For i = 2 To Sheets("Sheet3").Range("E" & Rows.Count).End(xlUp).Row
For j = 7 To Sheets("Sheet2").Range("E" & Rows.Count).End(xlUp).Row
Set rngsize = Sheets("Sheet3").Range("E" & i)
Set rngsize2 = Sheets("Sheet2").Range("E" & j)
Set rngmake = Sheets("Sheet3").Range("F" & i)
Set rngmake2 = Sheets("Sheet2").Range("F" & j)
Set rngprice = Sheets("Sheet3").Range("X" & i)
Set rngprice2 = Sheets("Sheet2").Range("X" & j)
If rngsize * 0.5 <= rngsize And rngsize2 + 1.5 >= rngsize Then
If rngmake2 * 0.5 <= rngmake And rngmake2 * 1.5 >= rngmake Then
Sheets("Sheet2").Range(Cells(rngprice.Row, rngprice.Column), Cells(rngprice.Row + 2, rngprice.Column)).Copy
Sheets("Sheet4").Range("F" & x).PasteSpecial Paste:=xlPasteValues
x = x + 3
End If
End If
Next j
Next i
End Sub
It runs, not sure if it works as intended though.
I've been working on a VBA script for a while now that goes through the values of a column and deletes all rows with values appearing only once (pretty much the inverse of deleting duplicates).
Column Headers to make explanation easier
There are numbers in the 'VTR' column that appear more than once. most appear just once.
I'd like the macro to delete all rows where the number in the 'VTR' column appears only once.(in the case of one of these numbers appearing more than once, the difference lies at the 'AFTARTKRZ' column where the value can either be (GAPNK or GAPN2) or RSLNV or RSVNK. (GAPNK or GAPN2 are the same thing)
i.e a row can appear either once with AFTARTKRZ,
(GAPNK or GAPN2)
-OR twice
either (GAPNKorGAPN2), RSLNV
or (GAPNKorGAPN2), RSVNK
OR thrice
(GAPNK or GAPN2), RSLNV, RSVNK.
I'd like to delete all those that appear only once (GAPNKorGAPN2)
Furthermore, I'd like to then add the values of the 'AFTARTKRZ' values of the duplicates to 2 extra columns at the end.
i.e, when a (GAPNK or GAPN2) appears two or threee other times, I'd like to input the 'AFTARTKRZ' column value in the 2 last columns at the end.
Something like this should be the final result
VTR|AFTARTKRZ | Add1 | Add2
11 |GAPNK |RSLNV | RSVNK| - VTR appeared thrice
12 |GAPN2 |RSLNV | | - Appeared twice as (GAPNKorGAPN2), RSLNV
13 |GAPNK |RSVNK | | - Appeared twice as (GAPNKorGAPN2), RSVNK
14 |GAPN2 | |
15 |GAPNK | |
16 |GAPN2 | |
The relevant part begins at '~~~~ Work on A
Sub Test()
Dim wb As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet
Dim RowsToTestC As Range, Delrange As Range
Dim i As Long, Lrow As Long, Lop As Long
Set ws1 = ThisWorkbook.Worksheets(1)
ThisWorkbook.ActiveSheet.Name = "A"
ws1.Copy ThisWorkbook.Sheets(Sheets.Count)
ThisWorkbook.ActiveSheet.Name = "B"
Set ws2 = ThisWorkbook.Worksheets(2)
ws1.Copy ThisWorkbook.Sheets(Sheets.Count)
ThisWorkbook.ActiveSheet.Name = "C"
Set ws2 = ThisWorkbook.Worksheets(3)
'~~~~ Work on C
Worksheets("C").Activate
With ActiveSheet
ActiveSheet.Range("A:AQ").RemoveDuplicates Columns:=6, Header:=xlNo
End With
Worksheets("C").Activate
Application.ScreenUpdating = False
'~~> Delete all but RSV
For Lrow = Range("D" & Rows.Count).End(xlUp).Row To 2 Step -1
If Range("D" & Lrow).Value = "GAPNK" Or Range("D" & Lrow) = "GAPN2" Then
Rows(Lrow).EntireRow.Delete
End If
Next Lrow
'~~~~ Work on B
Worksheets("B").Activate
With ActiveSheet
ActiveSheet.Range("A:AQ").RemoveDuplicates Columns:=6, Header:=xlNo
End With
Worksheets("B").Activate
Application.ScreenUpdating = False
'~~> Delete all but GAP
For Lrow = Range("D" & Rows.Count).End(xlUp).Row To 2 Step -1
If Range("D" & Lrow).Value = "RSVNK" Or Range("D" & Lrow) = "RSLNV" Then
Rows(Lrow).EntireRow.Delete
End If
Next Lrow
'~~~~ Work on A
Worksheets("A").Activate
Range("AR1").Select
ActiveCell.FormulaR1C1 = "RSVNK"
Range("AS1").Select
ActiveCell.FormulaR1C1 = "RSLNV"
With ws1
'~~> Get the last row which has data in Col A
Lop = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Loop through the rows
For i = 2 To Lop
'~~> For for multiple occurances
If .Cells(i, 6).Value <> "" And .Cells(i, 4).Value <> "" Then
If Application.WorksheetFunction.CountIf(.Columns(6), .Cells(i, 6)) = 1 And _
Application.WorksheetFunction.CountIf(.Columns(4), .Cells(i, 4)) = 1 Then
'~~> Store thee row in a temp range
If Delrange Is Nothing Then
Set Delrange = .Rows(i)
Else
Set Delrange = Union(Delrange, .Rows(i))
End If
End If
End If
Next
End With
End Sub
The logic of your code isn't valid.
The condition If Application.WorksheetFunction.CountIf(.Columns(4), .Cells(i, 4)) = 1 will always be False because this is the column containing your AFTARTKRZ keys. I don't know how many rows of data you have, but even in the 10 row sample you gave us the result is always greater than 1.
I do think you're making this unnecessarily complicated. Aren't you just trying to populate two lists: one of GAPs and the other of RSVs? You then want to create a third list where the GAP entries have corresponding RSV entries?
That could be done in a couple of short routines. You could do away with all of your sheet copying and row deleting and simply write your three lists directly to your sheets.
The code below shows you how this could be done. I've created 4 sheets, so you may need to add another to your Workbook: Sheet1 is your summary list (A), Sheet2 is your GAP list (B), Sheet3 is your RSV list (C), and Sheet4 holds the raw data.
Hopefully this code can get you started:
Option Explicit
Public Sub RunMe()
Const AFTARTKRZ_COL As Long = 4
Const VTR_COL As Long = 6
Dim data As Variant
Dim GAPs As Collection
Dim RSVs As Collection
Dim multis As Collection
Dim vtrKey As String
Dim multi(0 To 1) As Long
Dim i As Long, r As Long, c As Long
Dim v As Variant
Dim countRSV As Long
Dim output() As Variant
'Name your sheets.
'If you have fewer than 3 sheets or
'sheets already names A, B, C then this
'will throw an error.
Sheet1.Name = "A"
Sheet2.Name = "B"
Sheet3.Name = "C"
'Initialise the 3 collections
Set GAPs = New Collection
Set RSVs = New Collection
Set multis = New Collection
'Read the data - I've put my dummy data on Sheet4
data = Sheet4.UsedRange.Value2
'Iterate rows and place row in relevant collection
For r = 1 To UBound(data, 1)
vtrKey = CStr(data(r, VTR_COL))
On Error Resume Next 'removes duplicate entries
Select Case data(r, AFTARTKRZ_COL)
Case Is = "GAPNK", "GAPN2": GAPs.Add r, vtrKey
Case Is = "RSLNV": RSVs.Add r, vtrKey & "|RSLNV"
Case Is = "RSVNK": RSVs.Add r, vtrKey & "|RSVNK"
End Select
On Error GoTo 0
Next
'Check if each GAP also has RSVs
For Each v In GAPs
vtrKey = CStr(data(v, VTR_COL))
countRSV = 0
If Exists(RSVs, vtrKey & "|RSLNV") Then countRSV = countRSV + 1
If Exists(RSVs, vtrKey & "|RSVNK") Then countRSV = countRSV + 2
If countRSV > 0 Then
multi(0) = CLng(v)
multi(1) = countRSV
multis.Add multi, vtrKey
End If
Next
'Write your outputs
'Sheet C
ReDim output(1 To RSVs.Count + 1, 1 To UBound(data, 2))
For c = 1 To UBound(data, 2)
output(1, c) = data(1, c)
Next
i = 2
For Each v In RSVs
For c = 1 To UBound(data, 2)
output(i, c) = data(v, c)
Next
i = i + 1
Next
With Sheet3
.Cells.Clear
.Range("A1").Resize(UBound(output, 1), UBound(output, 2)).Value = output
.Columns.AutoFit
End With
'Sheet B
ReDim output(1 To GAPs.Count + 1, 1 To UBound(data, 2))
For c = 1 To UBound(data, 2)
output(1, c) = data(1, c)
Next
i = 2
For Each v In GAPs
For c = 1 To UBound(data, 2)
output(i, c) = data(v, c)
Next
i = i + 1
Next
With Sheet2
.Cells.Clear
.Range("A1").Resize(UBound(output, 1), UBound(output, 2)).Value = output
.Columns.AutoFit
End With
'Sheet A
ReDim output(1 To multis.Count + 1, 1 To 5)
output(1, 1) = "VTR"
output(1, 2) = "AFTARTKRZ"
output(1, 3) = "Add1"
output(1, 4) = "Add2"
i = 2
For Each v In multis
r = v(0)
output(i, 1) = data(r, VTR_COL)
output(i, 2) = data(r, AFTARTKRZ_COL)
output(i, 2) = data(r, AFTARTKRZ_COL)
Select Case v(1)
Case 1
output(i, 3) = "RSLNV"
output(i, 5) = "Appeared twice as (GAPNK or GAPN2), RSLNV"
Case 2
output(i, 3) = "RSVNK"
output(i, 5) = "Appeared twice as (GAPNK or GAPN2), RSVNK"
Case 3
output(i, 3) = "RSLNV"
output(i, 4) = "RSVNK"
output(i, 5) = "VTR appeared thrice"
End Select
i = i + 1
Next
With Sheet1
.Cells.Clear
.Range("A1").Resize(UBound(output, 1), UBound(output, 2)).Value = output
.Columns.AutoFit
End With
End Sub
Private Function Exists(col As Collection, key As String) As Boolean
Dim v As Variant
On Error Resume Next
v = col(key)
On Error GoTo 0
Exists = Not IsEmpty(v)
End Function
Please help me with some advice regarding the below excel. In the incipient form looks like this:
A B C
1 A1 ;100;200;300;400;500;
2 A2 ;716;721;428;1162;2183;433;434;1242;717;718;
3 A3 ;100;101;
And i want to reach this result:
A B C
1 A1 100
1 200
1 300
1 400
1 500
2 A2 716
2 721
2 428
2 1162
2 2183
2 433
2 434
2 1242
2 717
2 718
3 A3 100
3 101
I tried using this code, but it does not return the expected result.
Sub SliceNDice()
Dim objRegex As Object
Dim X
Dim Y
Dim lngRow As Long
Dim lngCnt As Long
Dim tempArr() As String
Dim strArr
Set objRegex = CreateObject("vbscript.regexp")
objRegex.Pattern = "^\s+(.+?)$"
'Define the range to be analysed
X = Range([a1], Cells(Rows.Count, "b").End(xlUp)).Value2
ReDim Y(1 To 2, 1 To 1000)
For lngRow = 1 To UBound(X, 1)
'Split each string by ";"
tempArr = Split(X(lngRow, 2), ";")
For Each strArr In tempArr
lngCnt = lngCnt + 1
'Add another 1000 records to resorted array every 1000 records
If lngCnt Mod 1000 = 0 Then ReDim Preserve Y(1 To 2, 1 To lngCnt + 1000)
Y(1, lngCnt) = X(lngRow, 1)
Y(2, lngCnt) = objRegex.Replace(strArr, "$1")
Next
Next lngRow
'Dump the re-ordered range to columns C:D
[c1].Resize(lngCnt, 2).Value2 = Application.Transpose(Y)
End Sub
Thanks in advance!
Try this:
Option Explicit
Sub DoSomething()
Dim i As Integer, j As Integer, k As Integer
Dim srcwsh As Worksheet, dstwsh As Worksheet
Dim sTmp As String, sNumbers() As String
Set srcwsh = ThisWorkbook.Worksheets("Sheet1")
Set dstwsh = ThisWorkbook.Worksheets("Sheet2")
i = 1
j = 1
Do While srcwsh.Range("A" & i) <> ""
sTmp = srcwsh.Range("C" & i)
sNumbers = GetNumbers(sTmp)
For k = LBound(sNumbers()) To UBound(sNumbers())
dstwsh.Range("A" & j) = srcwsh.Range("A" & i)
dstwsh.Range("B" & j) = srcwsh.Range("B" & i)
dstwsh.Range("C" & j) = sNumbers(k)
j = j + 1
Next
i = i + 1
Loop
Set srcwsh = Nothing
Set dstwsh = Nothing
End Sub
Function GetNumbers(ByVal sNumbers As String) As String()
Dim sTmp As String
sTmp = sNumbers
'remove first ;
sTmp = Left(sTmp, Len(sTmp) - 1)
'remove last ;)
sTmp = Right(sTmp, Len(sTmp) - 1)
GetNumbers = Split(sTmp, ";")
End Function
Note: i'd suggest to add error handler. For further information, please see: Exception and Error Handling in Visual Basic
This code will work for you
Sub SplitAndCopy()
Dim sh As Worksheet
Set sh = ThisWorkbook.Worksheets("YourTargetSheet")
Dim i As Long, j As Long, k As Long
k = 2
For i = 2 To Cells(Rows.Count, "A").End(xlUp).Row
For j = LBound(Split(Range("C" & i).Value, ";")) + 1 To UBound(Split(Range("C" & i).Value, ";")) - 1
sh.Range("A" & k).Value = Range("A" & i).Value
If j = LBound(Split(Range("C" & i).Value, ";")) + 1 Then
sh.Range("B" & k).Value = Range("B" & i).Value
End If
sh.Range("C" & k).Value = Split(Range("C" & i).Value, ";")(j)
k = k + 1
Next j
Next i
End Sub
I would rather go this way:
Private Type data
col1 As Integer
col2 As String
col3 As String
End Type
Sub SplitAndCopy()
Dim x%, y%, c%
Dim arrData() As data
Dim splitCol() As String
ReDim arrData(1 To Cells(1, 1).End(xlDown))
x = 1: y = 1: c = 1
Do Until Cells(x, 1) = ""
arrData(x).col1 = Cells(x, 1)
arrData(x).col2 = Cells(x, 2)
arrData(x).col3 = Cells(x, 3)
x = x + 1
Loop
[a:d].Clear
For x = 1 To UBound(arrData)
Cells(c, 2) = arrData(x).col2
splitCol = Split(Mid(arrData(x).col3, 2, Len(arrData(x).col3) - 2), ";")
' sort splitCol
For y = 0 To UBound(splitCol)
Cells(c, 1) = arrData(x).col1
Cells(c, 3) = splitCol(y)
c = c + 1
Next y
Next x
End Sub
I am not totally sure if you need your third column sorted, in case you can add a sorting function.