-1
MyFile = Dir(MyFolder)
    Do While MyFile <> ""
        Application.StatusBar = "Opening" & MyFile
        Set wbk = Workbooks.Open(MyFolder & MyFile, True, True)
        bFound = False
        For Each ws In wbk.Sheets
            If ws.Name = "Sheet 1" Then
                Range("B2").Select    'This gives us the first cell
                Do Until IsEmpty(ActiveCell)
                    For i = LBound(arr, 1) To UBound(arr, 1)
                        For j = LBound(arr, 2) To UBound(arr, 2)
                            If arr(i, j) <> "" And arr(i, j) <> ActiveCell.Value Then
                                For k = UBound(arr, 2) To j + 1 Step -1
                                    arr(k, i) = arr(k - 1, i)
                                Next k
                                arr(i, j) = ActiveCell.Value
                            End If
                            If arr(i, j) = "" Then
                                arr(i, j) = ActiveCell.Value
                                ActiveCell.Offset(1, 0).Select
                            End If
                            If arr(i, j) = ActiveCell.Value Then
                                ActiveCell.Offset(1, 0).Select
                            End If
                            If ActiveCell.Value = "" Then
                                Exit For
                            End If                                
                        Next j
                        If ActiveCell.Value = "" Then
                                Exit For
                        End If
                    Next i
                    Loop
            End If
        Next
    Loop

As you can see in the image I have an array of 4 elements, I got these elements into the array by iterating through the second column of a worksheet called "Sheet 1" from a workbook called "food.xlsx" in a folder that the user choses by selection. after the array places every element from column 2 of sheet "Sheet 1" and then places these elements into column 1 of itself, our array looks like the following image... enter image description here

We then move on to the next workbook called "food2.xlsx" which is located in the same folder. We look at column 2 of food2.xlsx. Column 2 of food2.xlsx has the exact same values at the exact same rows as column 2 of food.xlsx. The only difference is that in row 3 of column 2 in food2.xlsx, instead of having a value of "chocolate", there is a value of "vanilla". What am I trying to do is place "vanilla" in the location of the array where "chocolate" is currently located, this would be at arr(1,3). Then what I want is to push "chocolate" and every other value under it down one spot. So the array should end up like..

enter image description here

The part of the code that is NOT doing its job is the if statement that starts with "If arr(i, j) <> "" And arr(i, j) <> ActiveCell.Value Then"

IMPORTANT: I need this to work for any new encountered value, not just vanilla

coder101
  • 1
  • 4
  • 2
    It's best to [avoid using `Select` and `ActiveCell` and `Activate`](https://stackoverflow.com/questions/10714251/how-to-avoid-using-select-in-excel-vba). – BigBen Mar 10 '21 at 20:17
  • At first glance, you are setting `i = Lbound(arr, 2) ....` and `j = Lbound(arr, 2)...`. You are checking the boundaries of the same dimension. I think you want `i = Lbound(arr, 1) to Ubound(arr,1)`. This way you navigate the entire array. – basodre Mar 10 '21 at 20:19
  • @basodre Yes sorry that's actually what I originally had in my code, I recently changed it. But it still will not work with that – coder101 Mar 10 '21 at 20:20
  • @BigBen thanks for the advice. I will look into that for future code – coder101 Mar 10 '21 at 20:23
  • Why not use a dictionary? Trying to shuffle things around in an array sounds cumbersome. – SJR Mar 10 '21 at 20:31
  • @SJR I am fairly new to vba so I have never worked with dictionaries on vba. I will look into that in the future however I would like to make this array work and learn what I need to change – coder101 Mar 10 '21 at 20:33
  • Are you doing this with lots of workbooks and lots of different items? The fiirst thing is to follow BigBen's advice - your code is actually hard to follow for that reason. – SJR Mar 10 '21 at 20:34
  • Will foods always be in the same order? eg, could you have another table like `cola|apple|vanilla|honey|chocolate`? If so, how would you want the final table arranged? – Ron Rosenfeld Mar 10 '21 at 20:41
  • Yes there are multiple workbook, we iterate through them as we finish using their column 2 on "Sheet 1". "Sheet 1" is the only sheet we use from each workbook. The Activecell starts at "B2" every time we enter a new workbook's "Sheet1" that's why we select it after opening "Sheet 1". We iterate through column 2 until the ActiveCell has no element in it. – coder101 Mar 10 '21 at 20:42
  • @RonRosefeld if a food file such as the second workbook is not the same as the first workbook, it would have a very small difference. The only difference that could appear is that the second workbook has a element (food item) in it that is not present in first workbook. That is the only possible difference. The rest of the items are in the same order. That is why the second workbook has "Vanilla" in it. "Vanilla" makes the only difference between the second workbook and the first workbook. Every workbook after workbook 1 cannot have less items than workbook 1, only more items. – coder101 Mar 10 '21 at 20:48
  • 1
    Why not read the range into a VBA array (or dictionary), loop through the array, then write back to the sheet? "Dim aArrayList() As Variant" and "aArrayList = Range("A1:D4")". Finally, [A1] = aArrayList() . – cadvena Mar 10 '21 at 20:50
  • I think it would be much simpler to use a dictionary or an arrayList. Either of them would allow you to tell if the "new" item is present or not, and you can insert that item at the appropriate spot. Or you could just add all the unique items to the object; and then sort the results. – Ron Rosenfeld Mar 10 '21 at 20:52
  • Use an ArrayList not an Array. Arraylist has an InserAt method and can be converted to an array before writing back to Excel. – freeflow Mar 10 '21 at 20:53
  • I feel like I could make this array work seeing as though I got the other parts to work, if you do find a solution with arraylist however, I would like to see it. – coder101 Mar 10 '21 at 21:14
  • 'smee again. Don't you confuse `arr(i, j)` and `arr(j, i)` ? Work yourself through a really short example and check for all variable values after every step. You can watch values in the IDE. – Wolfgang Jacques Mar 10 '21 at 21:32
  • @WolfgangJacues sorry that was a typo. I didn't have that mistake on my actual code in the module – coder101 Mar 10 '21 at 21:52
  • I really think you ought to take a step back and try to describe the broader picture of what you are trying to accomplish. You posted some 36 lines of code and are trying to solve a very specific problem; I have the feeling that 36 lines is more than enough to solve the broader problem without getting bogged down in these picayune details. – Zev Spitz Mar 10 '21 at 22:23
  • How are you handling the possibility -- if at all -- that you may end up with more values than the size of the array? – Zev Spitz Mar 10 '21 at 22:25
  • Is the order of the elements important? Does it have to follow the order of the original elements? – Zev Spitz Mar 10 '21 at 22:29
  • @zevspitz the array is already much bigger than the amount rows ever needed so I won't run into that issue. and yes the order is important. The example I provided with the two images is how it should run – coder101 Mar 10 '21 at 22:31
  • NB: As the loop stands, it won't ever finish, because it never reassigns `MyFile = Dir(MyFolder)`. – Zev Spitz Mar 10 '21 at 22:39
  • FYI I don't think `Dir()` guarantees any file order, so the file with the "extra" item(s) could be the first file returned and not the second... – Tim Williams Mar 10 '21 at 22:49
  • @TimWilliams nothing in the code is giving me issues except the part I mentioned. – coder101 Mar 10 '21 at 23:02

2 Answers2

1

Unrelated note: I prefer the FileSystemObject API over the VBA Dir function; which you can use by adding a reference (Tools -> References...) to the Microsoft Scripting Runtime library.

I would suggest using a disconnected ADO recordset. Recordsets are commonly associated with pulling data from databases or other data sources; but we can construct and fill our own, and use the recordset's built-in sorting capabilities. This frees us from worrying about shifting elements back and forth within the array, or even from the proper position in which to insert the new element.

Add a reference (Tools -> References...) to Microsoft ActiveX Data Objects; choose the latest version -- usually 6.1.

Then, you could have code like the following:

' Define the shape of the recordset
Dim rs As New ADODB.Recordset
rs.Fields.Append "Entry", adVarChar, 100
rs.Fields.Append "FileIndex", adTinyInt
rs.Fields.Append "RowIndex", adTinyInt
rs.Open

' Loop over the files, and populate the recordset
MyFile = Dir(MyFolder)
Do While MyFile <> ""
    Dim fileIndex As Integer

    Application.StatusBar = "Opening" & MyFile
    Set wbk = Workbooks.Open(MyFolder & MyFile, True, True)

    Dim data As Variant
    data = wbk.Worksheets("Sheet 1").UsedRange.Columns(2).Value

    Dim ubnd As Integer
    ubnd = UBound(data, 1)

    Dim rowIndex As Integer
    For rowIndex = 1 To ubnd
        Dim entry As String
        entry = data(rowIndex, 1)
        
        rs.Find "Entry='" & entry & "'"
        If rs.BOF Or rs.EOF Then ' record hasn't been found or recordset is empty
            rs.AddNew _
                Array("Entry", "RowIndex", "FileIndex"), _
                Array(entry, rowIndex, fileIndex)
            rs.Update
        End If
        rs.MoveFirst
    Next
    
    wbk.Close
    MyFile = Dir
    fileIndex = fileIndex + 1
Loop

' Specify the sort order, first by the row within the file, then by the order in which
' the file was processed
rs.Sort = "RowIndex,FileIndex"

' Iterate over the data, and print it to the Immediate pane
rs.MoveFirst
Do Until rs.EOF
    Debug.Print rs("Entry")
Loop

Note that the elements are sorted first by the order in which they appear in their respective files, then by the order in which the file was processed.


Links

Excel

VBA

ADO

Zev Spitz
  • 13,950
  • 6
  • 64
  • 136
0

Since you're determined to use an array, here's an example of how to shift "rows" down to create an empty slot at a specified index:

Sub Tester()
    Dim arr
    arr = Range("A1:E10").Value  'get some data
    
    ShuffleDown arr, 3 'insert a blank row at index 3
    
    Range("G1:K10").Value = arr  'show the modified content
    
End Sub

'Create a blank row at InsertRowIndex in a 2-D array, by shifting content down
'Does not warn about content being lost from the last "row"
'  of the array if there's already content there !
Sub ShuffleDown(ByRef arr, InsertRowIndex As Long)
    Dim rw As Long, col As Long
    For rw = UBound(arr, 1) To InsertRowIndex Step -1
        For col = LBound(arr, 2) To UBound(arr, 2)
            If rw > InsertRowIndex Then
                arr(rw, col) = arr(rw - 1, col)
            Else
                arr(rw, col) = ""
            End If
        Next col
    Next rw
End Sub
Tim Williams
  • 154,628
  • 8
  • 97
  • 125
  • Hello. Thanks for your input. just after looking at this real quick, what if I don't know the index where the new value is being added. I see you called the ShuffleDown subroutine and you gave it an argument of "3". what if I don't know the exact position and I want the subroutine to figure it out. – coder101 Mar 11 '21 at 00:58
  • What would you be providing to the sub in order for it to figure it out? – Tim Williams Mar 11 '21 at 01:24
  • I was able to use the variable j. The code however did not work :/ I even tried manipulating it many times in many ways. Did it work on your end? – coder101 Mar 11 '21 at 02:34
  • I posted a working example, but I've not done anything else with it. If you've made modifications or it didn't work when incorporated into your other code then there's no way for me to tell what the problem is. I just noticed from your screenshots that your array has the items all in the first "Row" (ie, (1,1), (1,2), etc) whereas my code assumes they're in the first "column" (ie. (1,1), (2,1), etc) – Tim Williams Mar 11 '21 at 02:41
  • Yes I noticed the difference. I changed yours to match mine however I will change mine to avoid future confusion. – coder101 Mar 11 '21 at 03:00