Script below runs a array difference calculation then processes the data further if other criteria is met. I need to add one additional criteria to filter the data further before it logs the final output to Sheet1. Need to add the "Location" in column "K" so it filters the data first before it logs it to Sheet1.
Code in Module 1
Public Sub PopulateMyArr()
myArr = Sheet4.Range("I6:I500").Value
End Sub
Code in This Workbook
Private Sub Workbook_Open()
PopulateMyArr
End Sub
Code in Sheet4 (BA_Size)
Private Sub Worksheet_Calculate()
Dim keyCells As Range, i As Long, diff, cKey As Range
'exit if togglebutton not on
If Not Worksheets("BA_Size").ToggleButton1.Value Then Exit Sub
On Error GoTo safeexit
Application.EnableEvents = False
Set keyCells = Me.Range("I6:I500")
nextrow = Sheet1.Cells(Sheet1.Rows.Count, "A").End(xlUp).Row + 1
For i = 1 To UBound(myArr)
Set cKey = keyCells(i, 1)
If cKey.Value <> myArr(i, 1) Then
diff = (cKey.Value - myArr(i, 1))
'check value in Col L
Select Case cKey.EntireRow.Columns("L").Value
Case "John": diff = diff * cKey.EntireRow.Columns("O").Value
Case "Mary": diff = diff * cKey.EntireRow.Columns("P").Value
Case Else: diff = 0
End Select
Sheet1.Cells(nextrow, "A").Value = diff
nextrow = nextrow + 1
End If
Next i
safeexit:
PopulateMyArr
Application.EnableEvents = True
End Sub
Untested:
Private Sub Worksheet_Calculate()
Dim keyCells As Range, i As Long, diff, cKey As Range, kVal
'exit if togglebutton not on
If Not Worksheets("BA_Size").ToggleButton1.Value Then Exit Sub
On Error GoTo safeexit
Application.EnableEvents = False
Set keyCells = Me.Range("I6:I500")
nextrow = Sheet1.Cells(Sheet1.Rows.Count, "A").End(xlUp).Row + 1
For i = 1 To UBound(myArr)
Set cKey = keyCells(i, 1)
kVal = cKey.EntireRow.Columns("K").Value ' << read from K
If kVal >= 0 And kVal <= 1 Then ' << check the value
If cKey.Value <> myArr(i, 1) Then
diff = (cKey.Value - myArr(i, 1))
'check value in Col L
Select Case cKey.EntireRow.Columns("L").Value
Case "John": diff = diff * cKey.EntireRow.Columns("O").Value
Case "Mary": diff = diff * cKey.EntireRow.Columns("P").Value
Case Else: diff = 0
End Select
Sheet1.Cells(nextrow, "A").Value = diff
nextrow = nextrow + 1
End If
End If 'K value is between 0 and 1
Next i
safeexit:
PopulateMyArr
Application.EnableEvents = True
End Sub
Script below currently stores an array and then compares it to an RTD updated array and outputs if there is a change. If there is no change then it will not log the change. Works great, but now I need an output log of the difference if a change occurs rather than output of a changed value in the updated array.
Code in Module 1
Public myArr()
Public Sub
PopulateMyArr()
myArr = Sheet4.Range("I6:I500").Value
End Sub
Code in This Workbook
Private Sub Workbook_Open()
PopulateMyArr
End Sub
Code in Sheet4(BA_Size)
Private Sub ToggleButton1_Click()
End Sub
Private Sub Worksheet_Calculate()
Dim keyCells As Range
On Error GoTo safeexit
Application.EnableEvents = False
Set keyCells = Me.Range("I6:J500")
If Worksheets("BA_Size").ToggleButton1.Value = True Then
Dim i As Integer
For i = 1 To UBound(myArr)
If keyCells(i, 1).Value <> myArr(i, 1) Then
nextrow = Sheet1.Cells(Sheet1.Rows.Count, "A").End(xlUp).Row + 1
Sheet1.Cells(nextrow, "A").Value = Me.Cells(i + 5, "I").Value
End If
Next i
End If
safeexit:
PopulateMyArr
Application.EnableEvents = True
End Sub
I've got a sub representing a commandbutton of my userform, this userform has the perpose of listing (in a listbox) all unique items found in a column of a two-dimensional array. At frst I would like to implant an extra variable to hold and thus represent the number of times the unique item appears in the array. Secondly I would like the (Unique) items listed as:
Unique item 1 (number of appearances).
Example 1 (23)
Example 2 (39)
Example 3 (101)
Example 4 (9)
...
Example n (#)
Here is the code, can some body help me out?
Private Sub CommandButton5_Click()
Dim ws As Worksheet
Dim dictUnq As Object
Dim UnqList() As String
Dim aData As Variant
Dim vData As Variant
Dim pData As Variant
Dim i As Variant
Dim PrintString1() As String
i = 1
Set ws = ActiveWorkbook.Sheets("Sheet3")
Set dictUnq = CreateObject("Scripting.Dictionary")
Application.ScreenUpdating = False
Application.EnableEvents = False
With ws.Range("G2", ws.Cells(ws.Rows.Count, "G").End(xlUp))
If .Row < 2 Then Exit Sub 'No data
If .Cells.Count = 1 Then
ReDim aData(1 To 1, 1 To 1)
aData(1, 1) = .Value
Else
aData = .Value
End If
End With
SBI_Omschrijving.ListBox1.Clear
For Each vData In aData
If Len(vData) > 0 Then
If Not dictUnq.exists(vData) Then dictUnq.Add vData, vData
End If
Next vData
Debug.Print dictUnq(vData)
SBI_Omschrijving.ListBox1.List = dictUnq.keys
MsgBox "Unique findings: " & dictUnq.Count
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
Use a dictionary to store the count? This demonstrates the principle. Note in your example I think you may only be adding one column G so I don't know of you intended more?
Sub test()
Dim myArray()
myArray = ActiveSheet.Range("A1").CurrentRegion.Value
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = LBound(myArray, 1) To UBound(myArray, 1) 'Depending on column of interest. Loop that
If Not dict.Exists(myArray(i, 1)) Then
dict.Add myArray(i, 1), 1
Else
dict(myArray(i, 1)) = dict(myArray(i, 1)) + 1
End If
Next i
Dim key As Variant
For Each key In dict.keys
Debug.Print key & "(" & dict(key) & ")"
Next key
End Sub
Your example might be something like (can't test dictionary on a mac I'm afraid so coding in my head)
Sub test()
Dim aData()
Dim ws As Worksheet
Dim targetRange As Range
Dim lastRow As Long
Set ws = ActiveSheet
lastRow = ws.Cells(ws.Rows.Count, "G").End(xlUp).Row
If lastRow = 1 Then Exit Sub
Set targetRange = ws.Range("G2:G" & lastRow)
If targetRange.Cells.Count = 1 Then
ReDim aData(1 To 1, 1 To 1)
aData(1, 1) = targetRange.Value
Else
aData = targetRange.Value2
End If
Dim dictUnq As Object
Set dictUnq = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = LBound(aData, 1) To UBound(aData, 1) 'Depending on column of interest. Loop that
If Not dictUnq.Exists(aData(i, 1)) Then
dictUnq.Add aData(i, 1), 1
Else
dictUnq(aData(i, 1)) = dictUnq(aData(i, 1)) + 1
End If
Next i
Dim key As Variant
For Each key In dictUnq.keys
Debug.Print key & "(" & dictUnq(key) & ")"
Next key
End Sub
another possibility
Option Explicit
Private Sub CommandButton5_Click()
Dim dictUnq As Object
Set dictUnq = CreateObject("Scripting.Dictionary")
Dim cell As Range
With ActiveWorkbook.Sheets("Sheet3")
For Each cell In .Range("G2", .Cells(.Rows.Count, "G").End(xlUp))
dictUnq(cell.Value) = dictUnq(cell.Value) + 1
Next
End With
If dictUnq.Count = 0 Then Exit Sub
Dim key As Variant
With SBI_Omschrijving.ListBox1
.Clear
.ColumnCount = 2
For Each key In dictUnq.keys
.AddItem key
.List(.ListCount - 1, 1) = dictUnq(key)
Next
End With
MsgBox "Unique findings: " & dictUnq.Count
End Sub
The code below removes values and indexes from array. I am wondering on how to stop the code once the array index gets too less than 0. The code currently breaks at this point, and I am looking at ways on trying to handle this.
Dim ws As Worksheet
Dim cmbbox() As Variant 'or String
Private Sub btnUndo_Click()
Dim idx As Integer
'idx = UBound(cmbbox) - 1
If Not Len(Join(cmbbox, "")) = 0 Then 'if your array is not empty remove the last value from it
ReDim Preserve cmbbox(UBound(cmbbox) - 1)
'cmbbox(0) = cbDepartmentNotes.Value
'MsgBox (idx)
Else 'if your array is empty redim your array and add value from combobox
MsgBox ("Please select your note")
'ReDim Preserve cmbbox(UBound(cmbbox) + 1)
'cmbbox(UBound(cmbbox)) = cbDepartmentNotes.Value
End If
'MsgBox "You selected Item : " & cmbbox(UBound(cmbbox))
'ListBox1.List = cmbbox
txtDepartmentNoteTemplate.Text = Join(cmbbox, ", ")
End Sub
Private Sub UserForm_Initialize()
Dim rngDepartment As Range
Set ws = Worksheets("Sheet1")
'Populate Department combo box.
For Each rngDepartment In ws.Range("Departments")
cbDepartment.AddItem rngDepartment.Value
Next rngDepartment
UserForm1.cbDepartmentNotes.Enabled = False
UserForm1.txtDepartmentNoteTemplate.Enabled = False
End Sub
Private Sub CommandButton1_Click() ' adds value to array and displays them in text box
If Len(Join(cmbbox, "")) = 0 Then 'if your array is empty add the first value from combobox to it
ReDim cmbbox(0)
cmbbox(0) = cbDepartmentNotes.Value
Else 'if your array is not empty redim your array and add value from combobox
ReDim Preserve cmbbox(UBound(cmbbox) + 1)
cmbbox(UBound(cmbbox)) = cbDepartmentNotes.Value
End If
'MsgBox "You selected Item : " & cmbbox(UBound(cmbbox))
'ListBox1.List = cmbbox
txtDepartmentNoteTemplate.Text = Join(cmbbox, ", ")
End Sub
Private Sub cbDepartment_Change() 'combo box value display function
displayNote
End Sub
Private Sub cbDepartmentNotes_Change()
txtDepartmentNoteTemplate.Enabled = True
End Sub
Function displayNote() As String
Dim rngDepartmentNote As Range
Dim x As String
Set ws = Worksheets("Sheet1")
If cbDepartment.Value = "IT" Then
cbDepartmentNotes.Clear
For Each rngDepartmentNote In ws.Range(Cells(3, "A"), Cells(3, "A").End(xlDown))
cbDepartmentNotes.Enabled = True
cbDepartmentNotes.AddItem rngDepartmentNote.Value
x = cbDepartmentNotes.Value
displayNote = x
Next rngDepartmentNote
ElseIf cbDepartment.Value = "PST" Then
cbDepartmentNotes.Clear
For Each rngDepartmentNote In ws.Range(Cells(3, "B"), Cells(3, "B").End(xlDown))
cbDepartmentNotes.Enabled = True
cbDepartmentNotes.AddItem rngDepartmentNote.Value
txtDepartmentNoteTemplate.Enabled = True
x = cbDepartmentNotes.Value
displayNote = x
Next rngDepartmentNote
End If
End Function
I am working on a project, which takes a checksheet that the user creates and fills out
and, when the user runs a macro, creates a new workbook that extrapolates and expands the checksheet data, as shown here
What it does is it goes through each of those number labor codes, and runs down the checksheet for all the applicable items, addending them to the list.
Now...I have this working fine, and run through the basic testing. I save the checksheet as an array and pass it through to the new workbook, filtering and creating the new workbook line-by-line.
I just can't help but think that there's a much easier way to do this, as the way I'm doing it now just doesn't seem to be the simplest and most stable way.
I'm open to sharing my code I have so far, but was wondering if you were given this senario, how you would approach it.
Here is the link to my file: https://www.dropbox.com/s/2gobdx1rcabquew/Checksheet_Template_R3.0%20-%20StkOvrflw.xls
Main module, which checks for errors and corrects formatting:
Option Explicit
Public FamilyName As String
Public ModelName As String
Public TaskArray() As Variant
Public TaskArrayRowCount As Integer
Public TaskArrayColCount As Integer
Sub CreateTemplate()
Application.EnableEvents = False
Application.ScreenUpdating = False
'Main SubModule. Runs Formatting and Template Generation
Dim thisWB As Workbook
Dim TaskArray() As Variant
Dim i As Range
Dim MajMinYesNo As Boolean
Dim OPOYesNo As Boolean
If MsgBox("Are you ready to generate the Template?", vbYesNo, "Ready?") = vbNo Then
Application.EnableEvents = True
Application.ScreenUpdating = True
End
End If
MajMinYesNo = False
OPOYesNo = False
Set thisWB = ActiveWorkbook
FamilyName = thisWB.Names("Family_Name").RefersToRange
ModelName = thisWB.Names("Model_No").RefersToRange
Call CreateArray(thisWB)
'Scans Form_Type Column for "R", "S", or "A-E"
For Each i In Range("CS_FormType")
If i Like "[RS]" Then
MajMinYesNo = True
ElseIf i Like "[A-E]" Then
OPOYesNo = True
End If
Next
'Generates Templates As Needed
If MajMinYesNo Then
If MsgBox("Generate Major/Minor Template?", vbYesNo) = vbYes Then
Call MajorMinor_Generate.GenerateMajorMinor(thisWB)
End If
End If
If OPOYesNo Then
If MsgBox("Generate OPO Template?", vbYesNo) = vbYes Then
Call OPO_Generate.GenerateOPO(thisWB)
End If
End If
Application.EnableEvents = True
Application.ScreenUpdating = True
MsgBox ("DONE!")
End Sub
Sub CreateArray(thisWB As Workbook)
'Checks formatting and creates array TaskArray() with all the checksheet data
With thisWB.Sheets(1)
'Confirms equal number of rows in columns "CS_TaskNo", "CS_FormType", and "CS_Task"
If (Not Range("CS_TaskNo").Rows.count = Range("CS_FormType").Rows.count) _
Or (Not Range("CS_TaskNo").Rows.count = Range("CS_Task").Rows.count) Then
MsgBox ("Task_No, Form_Type, and Task_Desc row count does not match. Please fix and try again")
Application.EnableEvents = True
Application.ScreenUpdating = True
End
End If
Call FormatCheck
Application.Union(Range("CS_Heading"), Range("CS_TaskNo"), Range("CS_FormType"), Range("CS_Task"), Range("CS_LaborCodes"), Range("CS_Checks")).Name = "TaskArray"
TaskArrayRowCount = Range("TaskArray").Rows.count
TaskArrayColCount = Range("TaskArray").Columns.count
ReDim TaskArray(TaskArrayRowCount, TaskArrayColCount)
TaskArray = Range("TaskArray").Value
End With
End Sub
Sub FormatCheck()
'Checks for valid labor codes and Form Types
If (Not CheckFormType()) Or (Not CheckLC()) Then
MsgBox ("Errors found, please check red-highlighted cells")
Application.EnableEvents = True
Application.ScreenUpdating = True
End
End If
End Sub
Function CheckFormType()
'Returns False if there's a bad Form_Type entry in range "CS_FormType", True if all OK
Dim i As Range
Dim ReturnVal As Boolean
ReturnVal = True
For Each i In Range("CS_FormType")
Trim (UCase(i.Value))
If Not (i Like "[ABCDEFRS]") Then
Highlight (Cells(i.Row, i.Column))
ReturnVal = False
End If
Next
CheckFormType = ReturnVal
End Function
Function CheckLC()
'Returns False if there's a bad error code, True if all OK _
Formats labor code ranges to add spaces as needed and checks _
labor codes for proper format (###X or ##X). Skips any labor _
codes starting with "28X"
Dim LaborCode As String
Dim LaborCodeLength As Integer
Dim i As Range
Dim j As Integer
Dim LCCell As Range
Dim LCArray() As String
Dim ReturnVal As Boolean
ReturnVal = True
For Each i In Range("CS_LaborCodes")
Trim (UCase(i.Value))
LaborCode = i.Value
If Not Left(LaborCode, 3) Like "28?" Then
LaborCodeLength = Len(LaborCode)
'If string LaborCode is > 4, safe to assume it is a range of labor codes 123A-123F
Select Case LaborCodeLength
Case Is > 4
'Formats Labor Code Range String by adding spaces if necessary (i.e. 123A-123F to 123A - 123F)
For j = 2 To LaborCodeLength Step 1
If (IsNumeric(Mid(LaborCode, j, 1))) And Not IsNumeric(Mid(LaborCode, j + 1, 1)) And Not (Mid(LaborCode, j + 2, 1) = " ") Then
LaborCode = Left(LaborCode, j + 1) & " " & Mid(LaborCode, j + 2)
ElseIf IsNumeric(Mid(LaborCode, j, 1)) And Not (Mid(LaborCode, j - 1, 1) = " ") And Not IsNumeric(Mid(LaborCode, j - 1, 1)) Then
LaborCode = Left(LaborCode, j - 1) & " " & Mid(LaborCode, j)
End If
Next
i = LaborCode
LCArray = Split(LaborCode, " ")
'confirms the labor codes are valid
If (Not IsLaborCode(LCArray(0))) Or (Not IsLaborCode(LCArray(2))) Or (Not IsLaborCodeRange(LCArray(0), LCArray(2))) Then
Highlight (Cells(i.Row, i.Column))
ReturnVal = False
End If
Case 0 To 4
If Not (IsLaborCode(LaborCode)) Then
Highlight (Cells(i.Row, i.Column))
ReturnVal = False
End If
Case Else
Highlight (Cells(i.Row, i.Column))
ReturnVal = False
End Select
End If
Next
CheckLC = ReturnVal
End Function
Function IsLaborCode(LC As String) As Boolean
'returns True if Labor Code is valid, False if invalid _
Labor Code is valid if it is 2 or 3 numbers followed by a letter _
labor code format : ###X or ##X
If LC Like "###[A-Z]" Or LC Like "##[A-Z]" Then
IsLaborCode = True
Else
IsLaborCode = False
End If
End Function
Function IsLaborCodeRange(LCOne As String, LCTwo As String) As Boolean
'returns True if the LC range is valid, False if invalid. _
checks the numerical values to make sure they match and _
makes sure the letters are ascending
If (StrComp(Left(LCOne, Len(LCOne) - 1), Left(LCTwo, Len(LCTwo) - 1)) = 0) And LCOne < LCTwo Then
IsLaborCodeRange = True
Else
IsLaborCodeRange = False
End If
End Function
And here is the other module which actually takes the array and creates the new workbook:
Sub GenerateMajorMinor(thisWB As Workbook)
Dim newWB As Workbook
Dim MajMinArray() As Variant
Set newWB = Workbooks.Add
With newWB
Call FormatWorkbook
Call CreateMajMinArray(newWB, MajMinArray)
Call PopulateItemMaster(MajMinArray)
Call PopulateLaborLink(MajMinArray)
Call SaveFile(newWB, thisWB)
End With
End Sub
Sub SaveFile(newWB As Workbook, thisWB As Workbook)
'saves new workbook into the same file path as the checksheet
Dim i As Integer
Dim FileSavePath As String
Dim FamNameSave As String
FamNameSave = Replace(FamilyName, "/", "_")
i = 1
FileSavePath = thisWB.Path + "/Template (Minor and Major)_" + FamNameSave + ".xls"
a: If Dir(FileSavePath) <> "" Then
FileSavePath = thisWB.Path + "/Template (Minor and Major)_" + FamNameSave + "(" + CStr(i) + ").xls"
i = i + 1
GoTo a:
End If
newWB.SaveAs FileSavePath, FileFormat:=56
End Sub
Sub FormatWorkbook()
'Names and formats sheets
Sheets(1).Name = "Item_Master"
Sheets(2).Name = "Labor_Link"
With Sheets(1)
.Range("A1") = "Company_No"
.Range("B1") = "Family_Name"
.Range("C1") = "Form_Type"
.Range("D1") = "Record_Status"
.Range("E1") = "Task_Desc"
.Range("F1") = "Task_No"
.Range("G1") = "Task_Seq"
.Range("H1") = "Is_Parametric"
End With
With Sheets(2)
.Range("A1") = "Company_Name"
.Range("B1") = "Family_Name"
.Range("C1") = "Form_Type"
.Range("D1") = "Labor_Code"
.Range("E1") = "Print_Control"
.Range("F1") = "Record_Status"
.Range("G1") = "Task_No"
End With
End Sub
Sub CreateMajMinArray(newWB As Workbook, MajMinArray As Variant)
'creates array, removing any OPO/BTS labor codes
With Sheets(3)
Application.EnableEvents = True
Application.ScreenUpdating = True
Dim rng As Range
Set rng = .Range(.Range("A1"), .Cells(TaskArrayRowCount, TaskArrayColCount))
rng = TaskArray
For i = 1 To .Range("A1").End(xlDown).Row Step 1
If .Cells(i, 2) Like "[A-E]" Then
.Rows(i).Delete
i = i - 1
End If
Next
For i = 1 To .Range("A1").End(xlToRight).Column Step 1
If Left(.Cells(1, i), 3) Like "28E" Then
.Columns(i).Delete
i = i - 1
End If
Next
ReDim MajMinArray(.Range("A1").End(xlDown).Row, .Range("A1").End(xlToRight).Column)
MajMinArray = .Range(.Range("A1"), .Cells(.Range("A1").End(xlDown).Row, .Range("A1").End(xlToRight).Column)).Value
.Cells.Clear
End With
End Sub
Sub PopulateItemMaster(MajMinArray As Variant)
With Sheets(1)
'Populates "Item_Master" Sheet
For i = 2 To UBound(MajMinArray) Step 1
.Cells(i, 2) = FamilyName
.Cells(i, 3) = MajMinArray(i, 2)
.Cells(i, 4) = "1"
.Cells(i, 5) = MajMinArray(i, 3)
.Cells(i, 6) = MajMinArray(i, 1)
.Cells(i, 7) = MajMinArray(i, 1)
Next
End With
End Sub
Sub PopulateLaborLink(MajMinArray As Variant)
Dim i As Integer
Dim LaborCode As String
Dim RowCount As Long
Dim LCArray() As String
Dim LastLetter As String
Dim LastFormType As String
'Initializes RowCount and PrintControl
RowCount = 2
PrintControl = 10
With Sheets(2)
For i = 4 To UBound(MajMinArray, 2) Step 1
LaborCode = Trim(MajMinArray(1, i))
'If Labor Code String length is > 4, safe to assume that it is a range of labor codes
Select Case Len(LaborCode)
Case Is > 4
LCArray = Split(LaborCode, " ")
'checks to see if LCArray(0) and LCArray(2) has values
If LCArray(0) = "" Or LCArray(2) = "" Then
MsgBox ("Error with Labor Code range. Please check and re-run")
Application.EnableEvents = True
Application.ScreenUpdating = True
End
End If
LastLetter = Chr(Asc(Right$(LCArray(2), 1)) + 1)
LCArray(2) = Replace(LCArray(2), Right$(LCArray(2), 1), LastLetter)
Do
Call PrintLaborLinkLines(MajMinArray, LCArray(0), RowCount, i)
LastLetter = Chr(Asc(Right$(LCArray(0), 1)) + 1)
LCArray(0) = Replace(LCArray(0), Right$(LCArray(0), 1), LastLetter)
Loop Until LCArray(0) = LCArray(2)
Erase LCArray()
Case Is <= 4
Call PrintLaborLinkLines(MajMinArray, LaborCode, RowCount, i)
End Select
Next
End With
End Sub
Sub PrintLaborLinkLines(MajMinArray As Variant, LaborCode As String, RowCount As Long, i As Integer)
Dim PrintControl As Long
PrintControl = 10
With Sheets(2)
For x = 2 To UBound(MajMinArray) Step 1
If UCase(MajMinArray(x, i)) = "Y" Then
If LastFormType <> MajMinArray(x, 2) Then
PrintControl = 10
End If
.Cells(RowCount, 2) = FamilyName
.Cells(RowCount, 3) = MajMinArray(x, 2)
.Cells(RowCount, 4) = LaborCode
.Cells(RowCount, 5) = PrintControl
.Cells(RowCount, 6) = "1"
.Cells(RowCount, 7) = MajMinArray(x, 1)
RowCount = RowCount + 1
PrintControl = PrintControl + 10
LastFormType = MajMinArray(x, 2)
End If
Next
End With
End Sub
If restructuring the order of the data on the new sheet is possible it seems as though you could copy only visible cells and then write a simple loop to bring in any data that is not explicit (ie Labor Code).