I'm struggeling to figure out the best way to attack this problem. I'm looking to group worksheet tabs and color code them based on the suffix.
Eg:
Worksheet Names:
ToDo_XY
Done_ZY
ToDo_ZY
Done_XY
Should be:
ToDo_XY
Done_XY
ToDo_ZY
Done_ZY
I know that the worksheet name will end in "non alphanumeric character" in the 3rd last position then two letters and I need to group by the two letters.
I'm not sure if I should be using a collection, or a dictionary or somehow arrays.
Here is what I have so far:
Public Sub GroupLabSheets()
Call GetLabListFromTextFile
Dim ThirdLastCharStr As String, ThirdLastCharStrIsAlphaNumBool As Boolean, PossibleLabStr As String, PossibleLabStrExistsBool As Boolean
For Each ws In ActiveWorkbook.Sheets
ThirdLastCharStr = Mid(ws.Name, Len(ws.Name) - 3, 1)
ThirdLastCharStrIsAlphaNumBool = IsAlphaNumeric(ThirdLastCharStr)
PossibleLabStr = Right(ws.Name, 2)
PossibleLabStrExistsBool = mylabs.Exists(PossibleLabStr)
If ThirdLastCharStrIsAlphaNumBool = False And PossibleLabStrExistsBool = True Then
Debug.Print "Worksheet Name = " & ws.Name & " - Index = " & ws.Index
End If
Next ws
Dim WSArr As Variant
WSArr = Array("ToDo_XY", "Done_XY")
'WSArr.Move Before:=Sheets(1)
Dim i As Long
For i = LBound(WSArr) To UBound(WSArr)
Debug.Print Worksheets(WSArr(i)).Name
Worksheets(WSArr(i)).Tab.Color = WHLabTabColor
Worksheets(WSArr(i)).Move Before:=Sheets(1)
Next i
End Sub
Public Function IsAlphaNumeric(ByVal vInput As Variant) As Boolean
On Error GoTo Error_Handler
Dim oRegEx As Object
If IsNull(vInput) = False Then
Set oRegEx = CreateObject("VBScript.RegExp")
oRegEx.Pattern = "^[a-zA-Z0-9]+$"
IsAlphaNumeric = oRegEx.Test(vInput)
Else
IsAlphaNumeric= True 'Null value returns True, modify as best suits your needs
End If
Error_Handler_Exit:
On Error Resume Next
If Not oRegEx Is Nothing Then Set oRegEx = Nothing
Exit Function
Error_Handler:
Debug.Print "The following error has occured" & vbCrLf & vbCrLf & _
"Error Number: " & err.Number & vbCrLf & _
"Error Source: IsAlphaNumeric" & vbCrLf & _
"Error Description: " & err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occured!"
Resume Error_Handler_Exit
End Function
Try this:
Sub ArrangeSheets()
Dim i As Long, wb As Workbook, ws As Worksheet
Dim dict As Object, suffix, colors, col As Collection, n As Long
colors = Array(vbRed, vbYellow, vbGreen, vbBlue) 'colors to be applied (may need to add more...)
Set dict = CreateObject("scripting.dictionary")
Set wb = ThisWorkbook
'collect and group all matched worksheets according to their suffix
For Each ws In wb.Worksheets
If SortIt(ws) Then
suffix = Right(ws.Name, 2)
If Not dict.exists(suffix) Then dict.Add suffix, New Collection
dict(suffix).Add ws
End If
Next ws
'now loop over the groups and move all sheets in a group
' after the first sheet in that group
For i = 0 To dict.Count - 1
Set col = dict.Items()(i)
For n = 1 To col.Count
Set ws = col(n)
ws.Tab.Color = colors(i)
If n > 1 Then ws.Move after:=col(n - 1)
Next n
Next i
End Sub
'is this worksheet a candidate for sorting?
Function SortIt(ws As Worksheet) As Boolean
Dim nm As String
nm = UCase(ws.Name)
If Len(nm) >= 4 Then
SortIt = (Not Mid(nm, Len(nm) - 2, 1) Like "[A-Z0-9]") And _
Right(nm, 2) Like "[A-Z][A-Z]"
End If
End Function
Try this code:
Option Explicit
Sub RearrangeTabs()
Dim a() As String, i As Integer, j As Integer, buf As String, ws As Worksheet
Dim colour As Long
With ActiveWorkbook
ReDim a(1 To .Worksheets.Count, 1 To 2)
i = 1
For Each ws In .Worksheets
buf = ws.Name
' make sort key
a(i, 1) = Right(buf, 2) & IIf(Left(buf, 1) = "T", "A", "Z")
a(i, 2) = buf
i = i + 1
Next
' primitive bubble sort
For i = LBound(a, 1) To UBound(a, 1)
For j = LBound(a, 1) To UBound(a, 1)
If a(i, 1) < a(j, 1) Then
buf = a(i, 1): a(i, 1) = a(j, 1): a(j, 1) = buf
buf = a(i, 2): a(i, 2) = a(j, 2): a(j, 2) = buf
End If
Next j
Next i
colour = 3 'start ColorIndex (built-in set of colors [1..56])
For i = UBound(a, 1) To LBound(a, 1) Step -1
Set ws = .Worksheets(a(i, 2))
ws.Tab.ColorIndex = colour
ws.Move Before:=.Worksheets(1)
' increment ColorIndex for every odd i
If i Mod 2 = 1 Then colour = colour Mod 56 + 1
Next i
End With
End Sub
Before
After
Related
Kindly see below code where it takes too much time run for more than 30rows in a range. (its similar to knapsack algorithm requirements)
let me try to explain below in detail,
Input Base sheet: Column A having values (For ex: 1555),
Column B having its Assignment value (A1),
Column C & D its filter value which will perform against input data sheet file.
Program working concept:
it takes first row(2) data from base sheet and apply filter (C2 & D2 value) in input data sheet (Column A & B respectively) then it checks value in column C and it find best sum to match the value (1555) or nearest to it and after it assigns value (which is A1) against those rows and repeats the same for next rows.
I have posted image below.
Kindly refer for Input Base sheet and Input Data sheet and
copy the codes in another workbook.
Run the macro, Choose Base sheet and the Data sheet. Program would run and assigns in Input data sheet. It runs super fast in lesser rows when I have more rows it gets hang/takes too hours to run.
Help me to where it can be speed up.
Appreciate your supports.
Thanks
input base sheet
input data sheet:
Sub sample1()
Dim lrow As Integer
Dim frow As Integer
Dim row As Integer
Dim ar As Variant
Dim aar As Variant
Dim Sol(), csol()
Dim arr As Variant
Dim pos As Integer
Dim arow() As Integer
Dim rng As Range
Dim rn As Range
Dim r As Range
Dim k As Integer
Dim itr As Integer
Dim path As String
Dim tm_base As Workbook
Dim tm_data As Workbook
Dim sh_base As Worksheet
Dim sh_data As Worksheet
Dim sh As Worksheet
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Set sh = ActiveSheet
ReDim arr(0)
arr(0) = ""
path = FileSelection("Input Base")
If path = "" Then Exit Sub
Set tm_base = Workbooks.Open(path)
path = FileSelection("Input Data")
If path = "" Then Exit Sub
Set tm_data = Workbooks.Open(path)
Set sh_base = tm_base.ActiveSheet
Set sh_data = tm_data.ActiveSheet
lrow = sh_data.Cells(Rows.Count, "A").End(xlUp).row
frow = sh_base.Cells(Rows.Count, "A").End(xlUp).row
SortMacro ActiveSheet, sh_base.Range("A2:A" & frow), sh_base.Range("A1:G" & frow), 2
SortMacro ActiveSheet, sh_data.Range("C2:C" & lrow), sh_data.Range("A1:G" & lrow), 2
For row = 2 To frow
If sh_base.Cells(row, "H") <> "Done" Then
itr = 1
sh_data.Range("A1:G" & lrow).AutoFilter Field:=4, Criteria1:="="
op2:
sh_data.Range("A1:G" & lrow).AutoFilter Field:=1, Criteria1:=sh_base.Cells(row, "C").Value
sh_data.Range("A1:G" & lrow).AutoFilter Field:=2, Criteria1:=sh_base.Cells(row, "D").Value
Set rn = Nothing
On Error Resume Next
Set rn = sh_data.Range("C2:C" & lrow).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not rn Is Nothing Then
ReDim ar(0)
ReDim arow(0)
k = 1
For Each r In rn
ReDim Preserve arow(k)
ReDim Preserve ar(k)
ar(k) = r.Value
arow(k) = r.row
k = k + 1
Next
ReDim Sol(LBound(ar) To UBound(ar))
ReDim csol(LBound(ar) To UBound(ar))
limsum = sh_base.Cells(row, "A").Value
For i = LBound(ar) To UBound(ar)
If ar(i) > limsum Then
ar(i) = -1
End If
Next
maxsum = 0
findsum ar, Sol, csol, maxsum, limsum, UBound(ar), UBound(ar)
ss = ""
For i = 1 To Sol(0)
'ss = ss & sep & ar(sol(i))
'sep = ","
If Not arr(UBound(arr)) = "" Then
ReDim Preserve arr(UBound(arr) + 1)
End If
arr(UBound(arr)) = ar(Sol(i))
Next i
'MsgBox ss & " sum =" & maxsum
For j = LBound(arr) To UBound(arr)
pos = Application.Match(arr(j), ar, False)
If ar(pos - 1) > 0 Then
ar(pos - 1) = -1
End If
pos = arow(pos - 1)
If sh.Range("B1") = "Option 01" Then
sh_data.Cells(pos, "D") = sh_base.Cells(row, "B").Value
Else
sh_data.Cells(pos, "D") = sh_base.Cells(row, "B").Value & " " & Format(itr, "00")
End If
Next
ReDim arr(0)
arr(0) = ""
sh_base.Cells(row, "H") = "Done"
If sh.Range("B1") = "Option 02" Then
sh_data.Range("A1:G" & lrow).AutoFilter Field:=4, Criteria1:="="
Set rng = sh_data.Range("A1:A" & lrow).SpecialCells(xlCellTypeVisible)
If rng.Cells.Count > 1 Then
itr = itr + 1
GoTo op2
End If
End If
End If
sh_data.Range("A1:G" & frow).AutoFilter Field:=1
sh_data.Range("A1:G" & frow).AutoFilter Field:=2
sh_data.Range("A1:G" & lrow).AutoFilter Field:=4
End If
Next
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Sub findsum(ByVal a, ByRef Sol, ByRef csol, ByRef maxsum, ByRef limsum, si, maxcount, Optional s = 0, Optional lvl = 1, Optional dif = 100000, Optional minuscount = 0, Optional tsol, Optional j = 0)
' recursive sub
For i = LBound(a) To si
If a(i) > 0 Then
If s + a(i) > limsum Then findsum a, Sol, csol, maxsum, limsum, i - 1, maxcount, s, lvl + 1, dif, minuscount, tsol
s = s + a(i)
csol(lvl) = i
If s <= limsum Then
If s > maxsum Then ' we found a sum greater than current max we save it
maxsum = s
Sol(0) = lvl
For j = 1 To lvl
Sol(j) = csol(j)
Next j
End If
If i > LBound(a) Then ' pick another number
findsum a, Sol, csol, maxsum, limsum, i - 1, maxcount, s, lvl + 1, dif, minuscount, tsol
End If
End If
s = s - a(i)
If maxsum = limsum Then Exit For 'exit if exact match
End If
Next i
End Sub
Sub SortMacro(ws As Worksheet, rn As Range, rng As Range, ord As Integer)
ws.Sort.SortFields.Clear
ws.Sort.SortFields.Add Key:=rn, _
SortOn:=xlSortOnValues, Order:=ord, DataOption:=xlSortNormal
With ws.Sort
.SetRange rng
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Function FileSelection(file As String)
Dim path As String
Dim st As String
Dim i As Integer
Dim j As Integer
FileSelection = ""
With Application.FileDialog(3)
.title = "Select the " & file & " file"
.AllowMultiSelect = False
.InitialFileName = st
.Show
If .SelectedItems.Count = 0 Then
MsgBox "You didn't select the file!", vbExclamation, "Canceled"
Exit Function
Else
FileSelection = .SelectedItems(1)
End If
End With
End Function
You can't. I ran it. With 20 base data points and 100 data points you already have sub findsum called 79 million times. It's a combinatorial explosion and no amount of code tweaking will fix that. You'll have to find a better algorithm.
I try to work on a Project but it seems that it's far from my ability.
I need to Compare 2 workbooks containing 3 sheets ("WireList", "Cumulated BOM" and "BOM"), when I Browse File 1 and File 2 all sheets should compare at the same time and give the result in the format below:
I try a lot of codes but I am still a beginner and I hope if possible someone can help
Thank you very Much
Code Examples 1 : (Just to compare)
Option Explicit
Sub Compare()
'Define Object for Excel Workbooks to Compare
Dim sh As Integer, shName As String
Dim F1_Workbook As Workbook, F2_Workbook As Workbook
Dim iRow As Double, iCol As Double, iRow_Max As Double, iCol_Max As Double
Dim File1_Path As String, File2_Path As String, F1_Data As String, F2_Data As String
'Assign the Workbook File Name along with its Path
File1_Path = ThisWorkbook.Sheets(1).Cells(1, 2)
File2_Path = ThisWorkbook.Sheets(1).Cells(2, 2)
iRow_Max = ThisWorkbook.Sheets(1).Cells(3, 2)
iCol_Max = ThisWorkbook.Sheets(1).Cells(4, 2)
Set F2_Workbook = Workbooks.Open(File2_Path)
Set F1_Workbook = Workbooks.Open(File1_Path)
ThisWorkbook.Sheets(1).Cells(6, 2) = F1_Workbook.Sheets.Count
'With F1_Workbook object, now it is possible to pull any data from it
'Read Data From Each Sheets of Both Excel Files & Compare Data
For sh = 1 To F1_Workbook.Sheets.Count
shName = F1_Workbook.Sheets(sh).Name
ThisWorkbook.Sheets(1).Cells(7 + sh, 1) = shName
ThisWorkbook.Sheets(1).Cells(7 + sh, 2) = "Identical Sheets"
ThisWorkbook.Sheets(1).Cells(7 + sh, 2).Interior.Color = vbGreen
For iRow = 1 To iRow_Max
For iCol = 1 To iCol_Max
F1_Data = F1_Workbook.Sheets(shName).Cells(iRow, iCol)
F2_Data = F2_Workbook.Sheets(shName).Cells(iRow, iCol)
'Compare Data From Excel Sheets & Highlight the Mismatches
If F1_Data <> F2_Data Then
F1_Workbook.Sheets(shName).Cells(iRow, iCol).Interior.Color = vbYellow
ThisWorkbook.Sheets(1).Cells(7 + sh, 2) = "Mismatch Found"
ThisWorkbook.Sheets(1).Cells(7 + sh, 2).Interior.Color = vbYellow
End If
Next iCol
Next iRow
Next sh
'Process Completed
ThisWorkbook.Sheets(1).Activate
MsgBox "Task Completed - Thanks for Visiting OfficeTricks.Com"
End Sub
Code Example 2 :
Option Explicit
Sub test_CompareSheets_Adv()
ActiveWorkbook.Activate
If SheetExists("results") = False Then
Sheets.Add
ActiveSheet.Name = "results"
End If
If CompareSheets_Adv("Sheet3", "Sheet4") = True Then
MsgBox " Completed Successfully!"
Else
MsgBox "Process Failed"
End If
End Sub
Function CompareSheets_Adv(sh1Name$, sheet2name$) As Boolean
Dim vstr As String
Dim vData As Variant
Dim vitm As Variant
Dim vArr As Variant
Dim v()
Dim a As Long
Dim b As Long
Dim c As Long
On Error GoTo CompareSheetsERR
vData = Sheets(sh1Name$).Range("A1:T6817").Value
With CreateObject("Scripting.Dictionary")
.CompareMode = 1
ReDim v(1 To UBound(vData, 2))
For a = 2 To UBound(vData, 1)
For b = 1 To UBound(vData, 2)
vstr = vstr & Chr(2) & vData(a, b)
v(b) = vData(a, b)
Next
.Item(vstr) = v
vstr = ""
Next
vData = Sheets(sheet2name$).Range("A1:T6817").Value
For a = 2 To UBound(vData, 1)
For b = 1 To UBound(vData, 2)
vstr = vstr & Chr(2) & vData(a, b)
v(b) = vData(a, b)
Next
If .exists(vstr) Then
.Item(vstr) = Empty
Else
.Item(vstr) = v
End If
vstr = ""
Next
For Each vitm In .keys
If IsEmpty(.Item(vitm)) Then
.Remove vitm
End If
Next
vArr = .items
c = .Count
End With
With Sheets("Results").Range("a1").Resize(, UBound(vData, 2))
.Cells.Clear
.Value = vData
If c > 0 Then
.Offset(1).Resize(c).Value = Application.Transpose(Application.Transpose(vArr))
End If
End With
CompareSheets_Adv = True
Exit Function
CompareSheetsERR:
CompareSheets_Adv = False
End Function
Function SheetExists(shName As String) As Boolean
With ActiveWorkbook
On Error Resume Next
SheetExists = (.Sheets(shName).Name = shName)
On Error GoTo 0
End With
End Function
I have an obstacle to automatically retrieve the data that are unique from the New Info that are the not available inside the Masterlist and add into the Masterlist on a routine basis.
Are there any ways to setup formulas or macros to identify the list in the Masterlist that are not available in the New Info worksheet?
Above would be the Ideal Result
Feeling generous so i'll try help and hope you can follow along. if you need to know how to add module to VBA, i've added this at the bottom.
I have functions i've created which do various things so that you only need to write a few lines of code to accomplish the task. top section is the code and the bottom section are the functions which allow this task to be so easy!
the idea is:
You 'Extract' the data
You 'Transform' the data
You 'Load' the Data back to the spreadsheet
The code would look something like this:
'https://www.linkedin.com/in/syed-n-928b2490/
Option Base 1
Sub WorkWithData()
Dim dataArray1() As Variant ' empty array for data
Dim dataArray2() As Variant ' empty array for data
Dim combinedArray() As Variant ' empty array for data
'First Get the data from both sheets and combine the data sets together - note the columns must be same
dataArray1() = GetArr("MasterList")
dataArray2() = GetArr("New Info")
'dataArray2() = GetArr("New Info",,,,,"C:/users/documents/bob.xlsx") ' if you want to obtain data directly from an external workbook you can use this line instead
'join the two datas together and remove dupes
combinedArray() = UnionArr(dataArray1(), dataArray2(), , True)
'Specify the sheet you want to paste the data in
PasteArr "MasterList", combinedArray()
Erase combinedArray
Erase dataArray1
Erase dataArray2
End Sub
''''''''''''''''''''''''''''''''''''''''''''''
' General Functions
' created by: Syed Noshahi
' linked in: https://www.linkedin.com/in/syed-n-928b2490/
''''''''''''''''''''''''''''''''''''''''''''''
'------- ---------------------- ---------
'------- Get Data into an Array ---------
'------- ---------------------- ---------
Function GetArr(SheetName As String, Optional ColumnForSize As Long = 1, Optional RowForSize As Long = 1, Optional Rowstart As Long = 1, Optional ColStart As Long = 1, Optional sExternalWBFullName As String = "", Optional bLeaveFileOpen As Boolean = False, Optional lSpecifyRows As Long = 0, Optional lSpecifyCols As Long = 0) As Variant()
Dim vArray() As Variant
Dim ws As Worksheet
Dim wb As Workbook
Set wb = ThisWorkbook
On Error GoTo ErrH
If Len(sExternalWBFullName) > 0 Then
i = Len(sExternalWBFullName)
Do
i = i - 1
s = Mid(sExternalWBFullName, i, 1)
Loop Until s = "\" Or (i = 1)
If i <> 0 Then
sWBName = Right(sExternalWBFullName, Len(sExternalWBFullName) - i)
sWBPath = Replace(sExternalWBFullName, sWBName, "", , , 1)
For Each wbs In Application.Workbooks
If wbs.Name = sWBName Then
sWBPath = ""
Exit For
End If
Next
End If
End If
If Len(sWBPath) > 0 And Len(sWBName) > 0 Then
Set wb = Workbooks.Open(sExternalWBFullName, False, True)
ElseIf Len(sWBName) > 0 Then
Set wb = Workbooks(sWBName)
End If: Set ws = wb.Sheets(SheetName): On Error GoTo 0
With ws
If .FilterMode = True Then .ShowAllData
If lSpecifyRows > 0 Then
lRow = lSpecifyRows
Else
lRow = .Cells(.Rows.Count, ColumnForSize).End(xlUp).Row - Rowstart + 1
End If
If lSpecifyCols > 0 Then
lCol = lSpecifyCols
Else
lCol = .Cells(RowForSize, .Columns.Count).End(xlToLeft).Column
End If
If lRow > 1 Or lCol > 1 Then
vArray() = .Cells(Rowstart, ColStart).Resize(lRow, lCol).Value2
GetArr = vArray()
End If
End With
If Len(sWBName) > 0 And Not bLeaveFileOpen Then
wb.Close False
End If
EndFunction:
Exit Function
ErrH:
Debug.Print "Worksheet name '" & SheetName & "' not found."
Resume EndFunction
End Function
'------- -------------------- ---------
'------- Paste Array to Sheet ---------
'------- -------------------- ---------
Function PasteArr(SheetName As String, vArray() As Variant, Optional ColumnForSize As Long = 1, Optional bClearContents As Boolean = True, Optional bLastRow As Boolean, Optional bOmitFirstRow As Boolean, Optional sWBName As String = "", Optional lPasteCol As Long = 1, Optional lStartRow As Long = 1)
Dim ws As Worksheet
Set wb = ThisWorkbook
On Error GoTo ErrH
If Len(sWBName) > 0 Then Set wb = Workbooks(sWBName)
Set ws = ThisWorkbook.Sheets(SheetName): On Error GoTo 0
x = 0
With ws
If .FilterMode = True Then .ShowAllData
If bClearContents Then
If lPasteCol > 1 And ColumnForSize = 1 Then ColumnForSize = lPasteCol
lRow = .Cells(.Rows.Count, ColumnForSize).End(xlUp).Row
If lRow > 1 And Len(.Cells(lStartRow, lPasteCol)) > 0 Then .Cells(lStartRow, lPasteCol).Resize(lRow - lStartRow + 1, UBound(vArray, 2)).ClearContents
End If
If bOmitFirstRow Then
For i = LBound(vArray, 2) To UBound(vArray, 2)
vArray(LBound(vArray), i) = vArray(UBound(vArray), i)
vArray(UBound(vArray), i) = ""
Next
x = 1
End If
If Not (Not vArray()) Then
If bLastRow Then
If lPasteCol > 1 And ColumnForSize = 1 Then ColumnForSize = lPasteCol
lRow = .Cells(.Rows.Count, ColumnForSize).End(xlUp).Row + 1
.Cells(lRow, lPasteCol).Resize(UBound(vArray) - x, UBound(vArray, 2)) = vArray()
Else
.Cells(lStartRow, lPasteCol).Resize(UBound(vArray) - x, UBound(vArray, 2)) = vArray()
End If
End If
End With
EndFunction:
Exit Function
ErrH:
Debug.Print "Worksheet name '" & SheetName & "' not found."
Resume EndFunction
End Function
'------- -------------- ------
'------- Union an Array ------
'------- -------------- ------
Function UnionArr(arrTemp1(), arrTemp2(), Optional RemoveColumns As Boolean = True, Optional RemoveDuplicates As Boolean = False)
' Function requires two arrays of same column size. First array dictates the size
Dim k As Long
Dim r As Long
Dim vTempArr()
Dim vArray(): Dim vHoldingArray(1 To 1)
Dim Od1 As Object: Set Od1 = CreateObject("Scripting.Dictionary"): Od1.CompareMode = 1
If RemoveColumns Then
k = 1
m = 2
Else
k = 0
m = 1
End If
r = UBound(arrTemp1) + UBound(arrTemp2) - k
ReDim vArray(r, UBound(arrTemp1, 2))
For i = 1 To UBound(arrTemp1)
For j = 1 To UBound(arrTemp1, 2)
vArray(i, j) = arrTemp1(i, j)
Next
Next
i = i - 1
For l = m To UBound(arrTemp2)
For j = 1 To UBound(arrTemp2, 2)
vArray(i + l - k, j) = arrTemp2(l, j)
Next
Next
'if removing duplicates has been selected we remove where the entire Row is a dupe
If RemoveDuplicates Then
k = 1
' first get all the columns together and store in a dictionary
For i = 2 To UBound(vArray)
vHoldingArray(1) = ""
For j = 1 To UBound(vArray, 2)
vHoldingArray(1) = vHoldingArray(1) & vArray(i, j)
Next
If Not Od1.Exists(vHoldingArray(1) & "key") Then
k = k + 1
Od1(vHoldingArray(1) & "key") = 1
End If
Next
ReDim vTempArr(k, UBound(vArray, 2))
k = 1
Od1.RemoveAll
For i = 1 To UBound(vArray, 2)
vTempArr(k, i) = vArray(k, i)
Next
For i = 2 To UBound(vArray)
vHoldingArray(1) = ""
For j = 1 To UBound(vArray, 2)
vHoldingArray(1) = vHoldingArray(1) & vArray(i, j)
Next
If Not Od1.Exists(vHoldingArray(1) & "key") Then
Od1(vHoldingArray(1) & "key") = 1
k = k + 1
For j = 1 To UBound(vArray, 2)
vTempArr(k, j) = vArray(i, j)
Next
End If
Next
vArray() = vTempArr()
End If
UnionArr = vArray()
Erase vTempArr()
Erase vArray()
Set Od1 = Nothing
End Function
on Excel press Alt + F11 (opens VBA editor)
view --> Project explorer
on the top left hand side click your file name (in the project window)
insert --> module
Sub ExportDataTSV()
Dim BCS As Worksheet
Dim Ctrl As Worksheet
Dim ws As Worksheet
Dim FName As String
Dim insertValues As String
Application.ScreenUpdating = False
Set BCS = ThisWorkbook.Sheets(Sheet2.Name)
Set Ctrl = ThisWorkbook.Sheets(Sheet1.Name)
#If Mac Then
NameFolder = "documents folder"
If Int(Val(Application.Version)) > 14 Then
'You run Mac Excel 2016
folder = _
MacScript("return POSIX path of (path to " & NameFolder & ") as string")
'Replace line needed for the special folders Home and documents
folder = _
Replace(SpecialFolder, "/Library/Containers/com.microsoft.Excel/Data", "")
Else
'You run Mac Excel 2011
folder = MacScript("return (path to " & NameFolder & ") as string")
End If
FName = folder & "bcs_output.tsv"
#Else
folder = Environ$("userprofile")
Debug.Print folder
FName = folder & "Documents\bcs_output.tsv"
#End If
If Ctrl.Range("D9") = "" Or Ctrl.Range("D10") = "" Then
MsgBox "Please enter the Scenario Year and Scenario you wish to save and click again", vbOKOnly
Exit Sub
End If
Ctrl.Range("D9").Copy
BCS.Range("AS2").PasteSpecial Paste:=xlPasteValues
Ctrl.Range("D10").Copy
BCS.Range("AT2").PasteSpecial Paste:=xlPasteValues
With BCS
numrows = .Cells(.Rows.Count, 1).End(xlUp).Row
numcol = .Cells(2, Columns.Count).End(xlToLeft).Column
.Range("AS1").Value = "scenario_year"
.Range("AS2:AS" & numrows).FillDown
.Range("AT1").Value = "scenario"
.Range("AT2:AT" & numrows).FillDown
.Range("AU1").Value = "save_date"
.Range("AU2").Formula = "=NOW()"
.Range("AU2:AU" & numrows).FillDown
.Range("AU2:AU" & numrows).NumberFormat = "yyyy-mm-dd hh:mm"
For x = 2 To numrows
Set rng1 = .Range("A" & x & ":R" & x)
Set rng2 = .Range("AC" & x & ":AF" & x)
Set rng3 = .Range("AH" & x & ":AK" & x)
Set rng4 = .Range("AN" & x & ":AO" & x)
Set rng5 = .Range("AS" & x & ":AU" & x)
Set Data = Union(rng1, rng2, rng3, rng4, rng5)
insertValues = Join2D(ToArray(Data), Chr(9))
Debug.Print insertValues
Call ConvertText(FName, insertValues)
Next x
End With
With BCS
.Activate
.Range("A1").Select
End With
Ctrl.Activate
Application.ScreenUpdating = True
MsgBox "Cluster Data saved to your documents folder, please upload the file here: ", vbOKOnly
End Sub
Function ToArray(rng) As Variant()
Dim arr() As Variant, r As Long, nr As Long
Dim ar As Range, c As Range, cnum As Long, rnum As Long
Dim col As Range
nr = rng.Areas(1).Rows.Count
ReDim arr(1 To nr, 1 To rng.Cells.Count / nr)
cnum = 0
For Each ar In rng.Areas
For Each col In ar.Columns
cnum = cnum + 1
rnum = 1
For Each c In col.Cells
arr(rnum, cnum) = c.Value
rnum = rnum + 1
Next c
Next col
Next ar
ToArray = arr
End Function
Public Function Join2D(ByVal vArray As Variant, Optional ByVal sWordDelim As String = " ", Optional ByVal sLineDelim As String = vbNewLine) As String
Dim i As Long, j As Long
Dim aReturn() As String
Dim aLine() As String
ReDim aReturn(LBound(vArray, 1) To UBound(vArray, 1))
ReDim aLine(LBound(vArray, 2) To UBound(vArray, 2))
For i = LBound(vArray, 1) To UBound(vArray, 1)
For j = LBound(vArray, 2) To UBound(vArray, 2)
'Put the current line into a 1d array
aLine(j) = vArray(i, j)
Next j
'Join the current line into a 1d array
aReturn(i) = Join(aLine, sWordDelim)
Next i
Join2D = Join(aReturn, sLineDelim)
End Function
Function ConvertText(myfile As String, strTxt As String)
Dim objStream
Set objStream = CreateObject("ADODB.Stream")
With objStream
'.Charset = "utf-8"
.Open
.WriteText strTxt
.SaveToFile myfile, 2
'.Close
End With
'Set objStream = Nothing
End Function
I attempted the above to write the non-contiguous ranges to a tab delimited file. I get a 3004 error - Unable to write file from that code. I am not sure why it can't write the file and since I can't even write the file I can't tell if it will write each row of data until there are no more. Can anyone assist with at least helping me get the file to write?
You need to separate folder and "Documents\bcs_output.tsv" with a backslash. In MacOS I believe the path separator is ":" (colon), not "\" (backslash).
Hopefully the title is clear. I am trying to search through multiple tables on a single sheet. The information I am looking for is the same for all of the tables, just that the corresponding column is located in different spots (e.g. in one table the column I want to search is in I, while for another table it could be in O.) which makes it a bit more challenging for me.
I want to search through each column that has the same title (Load Number) and depending on its value, copy that entire row over to a sheet that corresponds with that value.
Below is what I have so far in VBA as well as a picture to hopefully clarify my issue.
Any help/advice is appreciated!
http://imgur.com/a/e9DyH
Sub Load_Number_Finder()
Dim ws As Worksheet
Dim i As Integer
Dim j As Integer
j = 1
Set ws = Sheets.Add(After:=Sheets("Master"))
ws.Name = ("Test Load " & j)
i = 1
Sheets("Master").Select
For Each cell In Sheets("Master").Range("M:M")
If cell.Value = "1" Then
j = 1
'Set WS = Sheets.Add(After:=Sheets("Master"))
'WS.Name = ("Test Load " & j)
matchRow = cell.Row
Rows(matchRow & ":" & matchRow).Select
Selection.Copy
Sheets("Test Load " & j).Select
ActiveSheet.Rows(i).Select
ActiveSheet.Paste
Sheets("Master").Select
i = i + 1
ElseIf cell.Value = "" Then
' 2, 3, 4, 5, cases
Else
' Something needs to go here to catch when it doesnt have a load number on it yet
End If
' Err_Execute:
' MsgBox "An error occurred."
Next
End Sub
Try this function. This should work for you. Let me know what the results are with your sheet. I made a mock up sheet and tested it, it worked. I can make changes if this is not exactly what you are looking for.
Option Explicit
Sub copyPaste()
Dim rowCount, row_ix, temp, i As Integer
Dim TD_COL_IX As Integer
Dim td_value As String
Dim td_values() As String
rowCount = Worksheets("Master").Cells(Rows.Count, "A").End(xlUp).Row
For row_ix = 1 To rowCount
temp = isNewTable(CInt(row_ix))
If temp > 0 Then
TD_COL_IX = temp
ElseIf TD_COL_IX > 0 Then
td_value = Worksheets("Master").Cells(row_ix, TD_COL_IX)
If Not td_value = "" Then
td_values = Split(td_value, " ")
For i = 0 To UBound(td_values)
If Not sheetExists("Test Load " & td_values(i)) Then
Sheets.Add.Name = "Test Load " & td_values(i)
End If
If Worksheets("Test Load " & td_values(i)).Cells(1, 1).Value = "" Then
Worksheets("Master").Range(Worksheets("Master").Cells(row_ix, 1), Worksheets("Master").Cells(row_ix, TD_COL_IX - 1)).Copy _
Destination:=Worksheets("Test Load " & td_values(i)).Cells(1, 1)
Else
Dim rowCount_pasteSheet As Integer
rowCount_pasteSheet = Worksheets("Test Load " & td_values(i)).Cells(Rows.Count, "A").End(xlUp).Row
Worksheets("Master").Range(Worksheets("Master").Cells(row_ix, 1), Worksheets("Master").Cells(row_ix, TD_COL_IX - 1)).Copy _
Destination:=Worksheets("Test Load " & td_values(i)).Cells(rowCount_pasteSheet + 1, 1)
End If
Next i
End If
End If
Next row_ix
End Sub
Function isNewTable(row_ix As Integer) As Integer
Dim colCount, col_ix As Integer
colCount = Worksheets("Master").Cells(row_ix, Columns.Count).End(xlToLeft).Column
For col_ix = 1 To colCount
If Not IsError(Worksheets("Master").Cells(row_ix, col_ix).Value) Then
If Worksheets("Master").Cells(row_ix, col_ix).Value = "LD #" Then
isNewTable = col_ix
Exit Function
End If
End If
Next col_ix
isNewTable = 0
End Function
' ####################################################
' sheetExists(sheetToFind As String) As Boolean
'
' Returns true if the sheet exists, False otherwise
' ####################################################
Public Function sheetExists(sheetToFind As String) As Boolean
Dim sheet As Worksheet
sheetExists = False
For Each sheet In Worksheets
If sheetToFind = sheet.Name Then
sheetExists = True
Exit Function
End If
Next sheet
End Function