Привет всем участникам зелёного форума. Учу словарик на VBA, поставил себе задачу посчитать суммы по статьям нарастающим итогом, но что то у меня идёт не так. Иду по списку, проверяю exists- ом, если да - то плюсую к 0 итем по ключу.
Не стал делать слишком много статей в файле, что бы не усложнять. Хочу понять, как сделать так что бы можно было идти циклом по массиву со статьями, и при срабатывании свойства exists, считалась сумма в нарастании по каждой статье, далее выгружалась в ("b4") (эта часть не проблема)
Код
Sub lknb()
'просуммировать значения в нарастании по ключам
Dim d1 As Object, i As Integer, j As Integer
Dim a, b, c
'пилим словарь
Set d1 = CreateObject("scripting.dictionary")
'массив с нарастающим итогом
a = Range("a4").CurrentRegion
'массив сттатей, которые попадут в нарастающий итог
b = Range("d4").CurrentRegion
For i = 1 To UBound(a, 1)
d1.Add a(i, 1), 0
Next
'прохожусь по статьям в массиве b. Если есть ключ сущестует, тогда
'к итему с 0 суммой прибавляется сумма привязанная к этому ключу
For i = 1 To UBound(b, 1)
If d1.Exists((a(1, 1))) Then d1(a(1, 1)) = d1(a(1, 1)) + b(i, 2)
Next
'массив для вставки сложенных в нарастании итемов (сумм) по ключам
'ReDim c(1 To UBound(a, 1), 1 To 1)
c = d1(a(1, 1))
Stop
End Sub
Sub lknb()
'просуммировать значения в нарастании по ключам
Dim d1 As Object, i As Integer, j As Integer
Dim a, b, c
'пилим словарь
Set d1 = CreateObject("scripting.dictionary")
'массив с нарастающим итогом
a = Range("a4").CurrentRegion
'массив сттатей, которые попадут в нарастающий итог
b = Range("d4").CurrentRegion
'For i = 1 To UBound(a, 1)
' d1.Add a(i, 1), 0
'Next
'прохожусь по статьям в массиве b. Если есть ключ сущестует, тогда
'к итему с 0 суммой прибавляется сумма привязанная к этому ключу
For i = 1 To UBound(b, 1)
' If d1.Exists((a(1, 1))) Then d1(a(1, 1)) = d1(a(1, 1)) + b(i, 2)
d1.Item(b(i, 1)) = d1.Item(b(i, 1)) + b(i, 2)
Next
'массив для вставки сложенных в нарастании итемов (сумм) по ключам
'ReDim c(1 To UBound(a, 1), 1 To 1)
'c = d1(a(1, 1))
c = d1.Items
Stop
End Sub
Option Explicit
'==================================================================================================
Sub DicTest()
Dim dic_1 As New Dictionary, dic_2 As New Dictionary, dic_3 As New Dictionary ' 3 словаря. Раннее связывание
Dim a2D_KeyValue() ' динамический массив Variant: Variant()
Dim x, r&, s&, iKey&, iValue&
' Определяем динамический массив, как двумерный (2 измерения) массив-таблицу. 6 "строк", 2 "столбца".
' В первом столбце будут КЛЮЧИ, а во втором - ЗНАЧЕНИЯ к ним.
ReDim a2D_KeyValue(1 To 6, 1 To 2)
a2D_KeyValue(1, 1) = 1: a2D_KeyValue(1, 2) = 1 ' "строка" 1. В "столбце" 1 значение 1, в "столбце" 2 значение 1
a2D_KeyValue(2, 1) = 2: a2D_KeyValue(2, 2) = 2 ' "строка" 2. В "столбце" 1 значение 2, в "столбце" 2 значение 2
a2D_KeyValue(3, 1) = 1: a2D_KeyValue(3, 2) = 3 ' "строка" 3. В "столбце" 1 значение 1, в "столбце" 2 значение 3
a2D_KeyValue(4, 1) = 2: a2D_KeyValue(4, 2) = 4 ' и так далее …
a2D_KeyValue(5, 1) = 3: a2D_KeyValue(5, 2) = 5
a2D_KeyValue(6, 1) = 4: a2D_KeyValue(6, 2) = 6
' Делаем аналог СУММЕСЛИ:
For r = 1 To UBound(a2D_KeyValue, 1) ' цикл от 1ой "строки" маасиа и до последней
iKey = a2D_KeyValue(r, 1) ' чтобы итоговая запись была понятнее, запоминаем очередной КЛЮЧ (значение 1го столбца очередной строки цикла) в целочисленную (т.к. мы знаем, что ключи у нас - это целые числа) переменную
iValue = a2D_KeyValue(r, 2) ' тоже самое делаем со ЗНАЧЕНИЕМ(значение 2го столбца очередной строки цикла). Переменная целочисленная по той же причине, что и выше
dic_1(iKey) = dic_1(iKey) + iValue ' собираем сумму по ключу
' dic_1(a2D_KeyValue(r, 1)) = dic_1(a2D_KeyValue(r, 1)) + a2D_KeyValue(r, 2) ' если не использовать переменные для ключа и значения, то запись выглядела бы так (вместо 3ёх строк)
Next r
' Можно записать чуть длиннее. И это будет то же самое
For r = 1 To UBound(a2D_KeyValue, 1)
iKey = a2D_KeyValue(r, 1)
iValue = a2D_KeyValue(r, 2)
dic_2.Item(iKey) = dic_2.Item(iKey) + iValue
Next r
' Можно записать совсем подробно
For r = 1 To UBound(a2D_KeyValue, 1)
iKey = a2D_KeyValue(r, 1)
iValue = a2D_KeyValue(r, 2)
If dic_3.Exists(iKey) Then ' если ключ iKey есть в словаре
s = dic_3(iKey) ' получаем накопительную сумму по ключу в целочисленную переменную
s = s + iValue ' прибавляем очередное значение к накопительной сумме
dic_3(iKey) = s ' заменяем значение по ключу на новое (меняем старую сумму на обновлённую)
Else ' если ключа нет в словаре
dic_3.add iKey, iValue ' Значение тут - это первый элемент накопительной суммы по ключу
End If
Next r
' Выведем словари в Immediate, чтобы убедиться, что они одинаковые
Debug.Print "Dic 1 =========="
For Each x In dic_1.Keys ' цикл по всем ключам словаря "dic_1"
Debug.Print x, dic_1(x) ' печатаем КЛЮЧ и ЗНАЧЕНИЕ по нему (накопительная сумма)
Next x
Debug.Print "Dic 2 =========="
For Each x In dic_2.Keys
Debug.Print x, dic_2(x)
Next x
Debug.Print "Dic 3 =========="
For Each x In dic_3.Keys
Debug.Print x, dic_3(x)
Next x
End Sub
'==================================================================================================
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Всем ещё раз привет. Всё же возникла проблема с выгрузкой одномерного массива на лист. Поэтому придумал такой вот велосипед в строках 32-34. Выложу сюда, вдруг кому пригодится:
К исходному файлу в 1 посте можно добавить еще несколько статей с суммами, что бы было понаглядней
Код
Sub lknb()
'просуммировать значения в нарастании по ключам
Dim d1 As Object, i As Integer, j As Integer
Dim a, b, c
Range("b1").EntireColumn.Clear
'пилим словарь
Set d1 = CreateObject("scripting.dictionary")
'массив с нарастающим итогом. КЛЮЧИ
a = Range("a4").CurrentRegion
'массив статей, которые попадут в нарастающий итог. ИТЕМЫ в 1 столбце массива
b = Range("d4").CurrentRegion
'циклом назначаем пару ключ/итем. Итемы будут = 0, потому что
'надо собрать сумму в нарастании из другого места
For i = 1 To UBound(a, 1)
d1.Add a(i, 1), 0
Next
'прохожусь по статьям в массиве b. Если есть ключ существует, тогда
'к итему с 0 суммой прибавляется сумма привязанная к этому ключу
For i = 1 To UBound(b, 1)
If d1.Exists(b(i, 1)) Then d1(b(i, 1)) = d1(b(i, 1)) + b(i, 2)
Debug.Print d1(b(i, 1))
Next
c = d1.Items
For i = 1 To UBound(a, 1)
Cells(i + 3, 2).Value = d1.Items()(i - 1)
Next
End Sub
c = d1.Items
Range("B4").Resize(UBound(c) + 1, 1).Value = WorksheetFunction.Transpose(c)
P.S. Желательно никогда не объявлять целочисленные переменные как As Integer. Лучше всегда объявляйте As Long. Мы сейчас с вами не в 1998 году (Это намёк на то, что у вас в компьютере сейчас гигабайты оперативной памяти, а не мегабайты). А ошибку как-нибудь обязательно получите, когда массив будет > 32767 элементов