Неправильные результаты со словарем VBA

Я новичок в VBA, и я получаю неправильные результаты, делая словарь в VBA.

Вход :

  • столбец B: идентификатор общества
  • столбец A: идентификаторы их магазинов
  • столбец C: суммы

Неправильные результаты со словарем VBA

Ожидаемый результат:

  • Столбец E: идентификатор обществ
  • Столбец F: хранит идентификатор (уникальные значения)
  • Столбец G: общее количество идентификаторов каждого магазина.

Неправильные результаты со словарем VBA

Что я получаю:

Неправильные результаты со словарем VBA

Пример: для идентификатора магазина FRPAN3 у меня должно быть 351,48.

Код :

Option Explicit 
Dim dico As Object, f As Worksheet, i&

Sub ValeursUniques()

Set dico = CreateObject("Scripting.Dictionary")
Set f = Sheets("Feuil1")

For i = 2 To f.Range("B" & Rows.Count).End(xlUp).Row
    dico(f.Range("B" & i).Value) = dico(f.Range("B" & i).Value) + Val(f.Range("C" & i))
Next i

Range("F2").Resize(dico.Count, 1) = Application.Transpose(dico.keys)
Range("G2").Resize(dico.Count, 1) = Application.Transpose(dico.items)
End Sub

Любая идея, почему я получаю такие результаты?

Можете ли вы показать результат, а не использовать изображения.

Nathan_Sav 22.03.2022 14:38

Прежде чем суммировать значения в словаре, вам нужно сначала Add новый ключ с начальным значением. Потом можно подвести итог. Проверить, как работают словари Словарь Excel VBA — полное руководство

Foxfire And Burns And Burns 22.03.2022 14:39

Да, вы ничего не добавляете в словарь. Вам нужно использовать .add для добавления и .exists для проверки наличия ключей. Посмотрите справку к словарю.

Nathan_Sav 22.03.2022 14:39

«FRPAIA у меня должно быть 321,7» — я не вижу, как это соотносится с вашими данными, и я не вижу, как ваш вывод соотносится с вашим вводом.

SJR 22.03.2022 14:40

Вам не нужно использовать Add. dico(f.Range("B" & i).Value) автоматически добавляет элемент.

SJR 22.03.2022 14:41

Добавление десятичных знаков к возвращаемым значениям, что это происходит? Будет ли добавлено 00 или есть скрытые десятичные дроби?

FaneDuru 22.03.2022 15:13

Вы добавляете значения столбца F, используя + Val(f.Range("F" & i)), но суммы, показанные на скриншоте, находятся в столбце C? Можете ли вы это прояснить? • В противном случае добавьте снимок экрана, показывающий также столбец F.

Pᴇʜ 22.03.2022 15:23
Преобразование HTML-таблицы в профессиональный документ Excel
Преобразование HTML-таблицы в профессиональный документ Excel
Это самый простой способ создания Excel из HTML-таблицы.
Импорт excel в laravel в базу данных
Импорт excel в laravel в базу данных
Здравствуйте, дорогой читатель, в этой статье я расскажу практическим и быстрым способом, как импортировать файл Excel в вашу базу данных с помощью...
2
7
76
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вал функция может не возвращать правильное значение. Если ваши значения в столбце F Val(f.Range("F" & i)) на самом деле не являются целыми числами, их десятичные дроби могут быть обрезаны!

В документации говорится

The Val function stops reading the string at the first character that it can't recognize as part of a number.

The Val function recognizes only the period ( . ) as a valid decimal separator. When different decimal separators are used, as in international applications, use CDbl instead to convert a string to a number.

Поэтому, если в вашем номере есть какой-либо символ, он будет обрезан. В вашем случае , считается символом, и поэтому ваши значения превращаются в целые числа, поскольку , не рассматривается как десятичный разделитель.

Вместо этого обязательно используйте Функции преобразования типов:

cDbl(f.Range("F" & i))

преобразует значение в число с плавающей запятой с двойной точностью.

Из документов .... «Функция Val распознает только точку ( . ) как допустимый десятичный разделитель. Когда используются разные десятичные разделители, как в международных приложениях, вместо этого используйте CDbl для преобразования строки в число». Я не уверен, применимо это или нет, не могу сказать, какие числа на самом деле суммирует ОП.

BigBen 22.03.2022 14:59

Если это будет проблемой, значение будет транковым, а не округленным, а общая сумма на ключ словаря должна быть меньше, но это больше...

FaneDuru 22.03.2022 15:12

@FaneDuru Истинно, если в данных нет чего-то странного, например "2 45 7", которое Val превращается в 2457. Тем не менее Val в любом случае плохой выбор.

Pᴇʜ 22.03.2022 15:27

Используя cDb1, я получаю хорошие результаты! Всем большое спасибо :)

mfau 28.03.2022 10:39

Уникализируйте данные с помощью словаря

  • Если значение в первом уникальном столбце (в данном случае столбец 2) является значением ошибки или пустым,
    запись не будет включена.
  • Если значение в других уникальных столбцах (в данном случае только в столбце 1) является значением ошибки,
    он будет преобразован в Empty (неявно).
  • Если значение в столбце «Значение» (в данном случае столбец 3) не является числом,
    Вместо этого будет использоваться 0 (ноль).
  • Настройте (поиграйте) значения в разделе констант.
Option Explicit

Sub UniquifyData()
    
    ' Source
    Const sName As String = "Feuil1"
    Const sFirstCellAddress As String = "A1"
    Dim uCols As Variant: uCols = VBA.Array(2, 1)
    Const svCol As Long = 3
    ' Destination
    Const dName As String = "Feuil1"
    Const dFirstCellAddress As String = "E1"
    ' Both
    Const Delimiter As String = "@"
    Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
    
    ' Reference the source range and write its values to the source array.
    
    Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
    Dim srg As Range: Set srg = sws.Range(sFirstCellAddress).CurrentRegion
    Dim Data As Variant: Data = srg.Value
    
    Dim srCount As Long: srCount = UBound(Data, 1)
    Dim cCount As Long: cCount = UBound(Data, 2)
    
    ' Write the headers from the source array to the headers array.
    
    Dim cUpper As Long: cUpper = UBound(uCols)
    Dim Headers As Variant: ReDim Headers(1 To cUpper + 2)
    
    Dim c As Long
    
    For c = 0 To cUpper
        Headers(c + 1) = Data(1, uCols(c))
    Next c
    Headers(cCount) = Data(1, svCol)
    
    ' Write the unique values from the source array to a dictionary.
    
    Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
    dict.CompareMode = vbTextCompare
    
    Dim Key As Variant
    Dim sString As String
    Dim r As Long
    
    For r = 2 To srCount
        For c = 0 To cUpper
            Key = Data(r, uCols(c))
            If c = 0 Then
                If Not IsError(Key) Then
                    If Len(Key) > 0 Then
                        sString = CStr(Key)
                    End If
                End If
                If Len(sString) = 0 Then Exit For
            Else
                If IsError(Key) Then Key = ""
                sString = sString & Delimiter & CStr(Key) ' join uniques
            End If
        Next c
        If Len(sString) > 0 Then
            If IsNumeric(Data(r, svCol)) Then
                dict(sString) = dict(sString) + Data(r, svCol)
            Else
                If Not dict.Exists(sString) Then dict(sString) = 0
            End If
            sString = ""
        End If
    Next r
    
    ' Define the destination array.
    
    Dim drCount As Long: drCount = dict.Count + 1
    
    ReDim Data(1 To drCount, 1 To cCount)
    
    ' Write the headers from the headers array to the destination array.
    
    For c = 1 To cCount
        Data(1, c) = Headers(c)
    Next c
    
    ' Write the values from the dictionary to the destination array.
    
    r = 1
    
    For Each Key In dict.Keys
        r = r + 1
        ' Write uniques.
        uCols = Split(Key, Delimiter) ' split uniques
        For c = 0 To cUpper
            Data(r, c + 1) = uCols(c)
        Next
        ' Write value.
        Data(r, cCount) = dict(Key)
    Next Key
    
    ' Write the values from the destination array to the destination range.
    
    Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
    With dws.Range(dFirstCellAddress).Resize(, cCount) ' reference first row
        ' Write data.
        .Resize(drCount).Value = Data
        ' Clear below.
        .Resize(dws.Rows.Count - .Row - drCount + 1).Offset(drCount).Clear
        ' Apply some formatting.
        '.Font.Bold = True ' headers
        '.EntireColumn.AutoFit ' columns
    End With
    
    ' Inform.
     
    MsgBox "Data uniquified.", vbInformation

End Sub

Другие вопросы по теме