-1

I'm having problem with the following line of code:

    Set DICT = RowMap(Range(Workbooks("A").Sheets(1).Cells(ITEM_NO_ROW, _
ITEM_NO_COLUMN), Workbooks("A").Sheets(1).Cells(ITEM_NO_ROW + 1, ITEM_NO_COLUMN).End(xlDown)))

This code calls RowMap. I put a break at "End Function" of RowMap and check the count of rv and RowMap in the Watch Window. Both counts are 84 as they should be. However, as soon as I hit F8 which takes me to the main routine, and check the count of DICT, it is 85, not 84.

Shouldn't DICT be exactly the same as RowMap or rv? Why is the count of DICT incremented by 1? Which line of code makes it do that? I am completely lost.

I don't know if this info would help or not. The above Set DICT line is wrapped in a "For each cell in rng" loop and it is the cell that is added to the end of the DICT.

Any help will be greatly appreciated.

Function RowMap(rng1 As Range) As Object
'store item no and price in dictionary

    Dim rv As Object
    Dim c As Range
    Dim v As long
    On Error Resume Next

    Set rv = Nothing

    Set rv = CreateObject("scripting.dictionary")
    For Each c In rng1.Cells
        v = c.Value
        If Not rv.Exists(v) Then
            rv.Add v, c.Offset(0, 4) 'add item no and price
        Else
            MsgBox "Duplicate value detected in " & Book_Name & "!"
            Exit For
        End If
        Next c

    Set RowMap = rv

End Function

    For Each wk In Application.Workbooks

    If Left(wk.Name, 6) = "All FE" Then

        ERROR_Sheet_No = ERROR_Sheet_No + 1

        For Each sh In wk.Sheets

            Set Report_Last_Cell = sh.Cells(5000, 3).End(xlUp)

            'sort the data by group code
            Set rng = sh.Range(sh.Cells(4, 1), Report_Last_Cell.Offset(0, 4))

            rng.Sort key1:=sh.Cells(4, 4), order1:=xlAscending, Header:=xlNo

            Set rng = sh.Range(sh.Cells(4, 3), Report_Last_Cell)

            For Each cell In rng
                If cell.Value <> "LAVENDER" And cell.Value <> "CLOSED" And cell.Value <> "VOID" And cell.Value <> "NO SALE" And _
                    InStr(cell.Value, "DISCOUNT") = 0 And InStr(cell.Value, "DEPOSIT") = 0 And Len(cell) <> 0 Then

                    Group_Code = cell.Offset(0, 1).Value

                    If Group_Code <> Old_Group_Code Then 'open the PHOTO_QUOTE file
                        'close the old PHOTO_QUOTE file first
                        On Error Resume Next
                        Workbooks(File_Prefix & Old_Group_Code & ".xlsx").Close
                        On Error GoTo 0

                        'open the PHOTO QUOTE file if exists
                        If Len(Dir(Flower_Path & File_Prefix & Group_Code & ".xlsx")) <> 0 Then 'if file is found
                            Workbooks.Open Flower_Path & File_Prefix & Group_Code & ".xlsx"

                            Photo_Quote_Book_Name = File_Prefix & Group_Code & ".xlsx"
                            On Error Resume Next
                            DICT.RemoveAll
                            Set DICT = Nothing

                            Set DICT = RowMap(Range(Workbooks(Photo_Quote_Book_Name).Sheets(1).Cells(PHOTO_QUOTE_ITEM_NO_ROW, _
                                PHOTO_QUOTE_ITEM_NO_COLUMN), Workbooks(Photo_Quote_Book_Name).Sheets(1).Cells(PHOTO_QUOTE_ITEM_NO_ROW + 1, PHOTO_QUOTE_ITEM_NO_COLUMN).End(xlDown)))
                            On Error GoTo 0

                            'check if ITEM NO exists
                            If Not DICT.Exists(cell.Value) Then
                                Copy_to_ERROR_sheet sh.Name, ERROR_Sheet_lastrow, 0, 0, 255


                            'check if price matches
                            ElseIf cell.Offset(0, 3).Value <> DICT(cell.Value) Then
                                Copy_to_ERROR_sheet sh.Name, ERROR_Sheet_lastrow, 0, 255, 0
                            End If


                        Else 'if the PHOTO_QUOTE file doesn't exist, copy shop, date, voucher no, item no, price to
                        ' ERROR_BOOK_NAME and change color to red

                            Copy_to_ERROR_sheet sh.Name, ERROR_Sheet_lastrow, 255, 0, 0
                        End If 'If Len(Dir(Flower_Path & File_Prefix & Group_Code & ".xlsx")) <> 0 Then

                        Old_Group_Code = Group_Code
                    End If ' If Group_Code <> Old_Group_Code Then


                End If 'If cell.Value <> "LAVENDER" And cell.Value <> "CLOSED" And cell.Value <> "VOID" And cell.Value <> "NO SALE" And _
                InStr(cell.Value, "DISCOUNT") = 0 And InStr(cell.Value, "DEPOSIT") = 0 And Len(cell) <> 0 Then

            Next 'For Each cell In rng


        Next 'For Each sh In wk

    End If 'If Left(wk.Name, 6) = "All FE" Then

Next 'For Each wk In Application.Workbooks

Close_PHOTO

Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True

End Sub 'Check_Price
Community
  • 1
  • 1
joehua
  • 725
  • 3
  • 10
  • 25
  • There's nothing there which requires On Error Resume Next so I'd remove that to allow any errors to make themselves known. It would be useful to show exactly where in the calling sub you're taking the count from - a few more relevant lines from that procedure would help – Tim Williams Jan 24 '17 at 05:35
  • I'm running this code, and with my test I got 4 for both `RowMap` and `DICT`, what do you have at your code which is not posted ? do you have values inside `rng1` which are not numeric ? – Shai Rado Jan 24 '17 at 06:01
  • 1
    Although this code has so many lovely possibilities of errors such as type mismatch; error values, merged cells with zero value and the best one , a Range as the key's value but count mismatch is something that I cant reproduce. – cyboashu Jan 24 '17 at 06:12
  • Thanks for the comments. That "Set DICT" is the first time DICT shows up in the code (well, except the two test lines DICT.RemoveAll/Set DICT = Nothing.) Thus, I did not think the code before it is relevant. Anyway, I have posted the rest of the code. Basically, I want to find out if items from one file exist in another file. Using Range.Find would take more than 20 minutes. The dictionary method is much faster but it's not fully working yet. – joehua Jan 24 '17 at 07:12
  • Comment out all your `On Error Resume Next` both in the function and inside the loop. Add `Debug.Print "function", rv.Count` just before the last line in the function, and in the main code add `Debug.Print "main", DICT.Count` immediately after the call to the function. Where/how did you declare DICT ? – Tim Williams Jan 24 '17 at 07:13
  • Thanks. I removed "on error resume next" and now the count is 84. Why? I thought "on error resume next" just have Excel ignore the errors and other code should run as usual, not affected by the errors. – joehua Jan 24 '17 at 07:38
  • It's impossible to explain why it's now the same without knowing precisely how you arrived at the counts which were different. How did you previously get the 84 and 85? Note it's not difficult to add new keys accidentally when using the Watch window... e.g. https://stackoverflow.com/questions/21573320/error-this-key-is-already-associated-with-an-element-of-this-collection/21573515#21573515 and https://stackoverflow.com/questions/18733780/dictionary-in-vba-is-created-with-empty-key-value-pair/37468027#37468027 – Tim Williams Jan 24 '17 at 18:15
  • In the Watch window, I monitored DICT. I expanded it. So, it showed all the items in DICT (item 1, item 2, item 3, etc.). It also showed the DICT property Count. When Count was 84, I could see item 84 listed and its value. When Count was 85, I saw the value of item 85. and it was the value of cell.value, which was not in the rng1. I had also tried you Debug.Print method. It gave same result (same count) as what I saw in the Watch window. – joehua Jan 25 '17 at 03:38
  • It may be easy to accidently add keys. However, in my case, the only code that was executed between rv or RowMap, whose count was 84, and DICT, whose count was 85, was "End Function". As I said, both counts of rv and RowMap were 84. As soon as I hit F8 to execute "End Function", which returned RowMap to DICT, the count of DICT became 85. There was not other code being executed in between. – joehua Jan 25 '17 at 03:54
  • It's not your code which adds the "extra" item, it's using the Watch window to check properties of the Dictionary which does it. – Tim Williams Jan 25 '17 at 17:39
  • See my answer for what I'm suggesting is maybe your problem here – Tim Williams Jan 25 '17 at 17:57

2 Answers2

4

Here's an example of what can happen if you're not careful using the Watch window when working with a Dictionary.

Enter this code in a module and set a break and two watches as indicated :

Sub Tester()

    Dim dict As Object
    Set dict = CreateObject("scripting.dictionary")

    dict.Add "A", 1
    dict.Add "B", 2
    dict.Add "C", 3  '<<< put a break here
    dict.Add "D", 4

    Debug.Print dict("D")    '<< put a watch on `dict("D")`
    Debug.Print dict.Count   '<< put a watch on `dict`

End Sub

Now run to the break and check the Watch window - even though your code is still waiting on the break (and the "C" key is not added yet), your dictionary already has an empty "D" slot (and count is 3, not 2).

enter image description here

Even if you delete the dict.Add "D", 4 from your code, the watch on dict("D") will remain in the Watch window (unless you actively delete it) and will keep adding that "extra" key...

Tim Williams
  • 154,628
  • 8
  • 97
  • 125
0

Can't comment yet as I don't have enough reputation:

I think I have seen this before and suspect it is a result of debugging. Have you tried outputting (e.g. msgbox) RowMap.Count after the function call rather than checking whilst debugging to see what you get?

BoffWx
  • 106
  • 4
  • Thanks for the comment. I tried the msgbox and it says 84. In fact, I can see all 84 items in the Watch Window and they are what they should be because they are from another file which is open. So, I can see them all. The 85th item is NOT in that file, it is NOT in rng1, and it is NOT in RowMap nor rv. That's why I'm puzzled as to why I simply hit F8 to exit the function and one item is added to DICT. – joehua Jan 24 '17 at 07:11
  • @yky Could this be an explanation: [link]http://stackoverflow.com/questions/11400898/dictionary-object-adding-items-before-add-is-called – BoffWx Jan 24 '17 at 08:59
  • Thanks, Boffwx. I think you found the answer. – joehua Jan 25 '17 at 04:02