Страницы: 1
RSS
Функция CountIf для ключей словаря
 
Доброго времени суток, уважаемые форумчане. Давно не обращался на наш форум со своими "хотелками", как-то сам справлялся ;) , но вот вылез маленький вопросик. Итак, имеем массив в котором ключами являются даты:  
Код
 Set dicData = CreateObject("Scripting.Dictionary"): dicData.CompareMode = 1
    x = Range("A1:B" & Cells(Rows.Count, 2).End(xlUp).Row).Value
        For i = 1 To UBound(x)
            dicData.Add x(i, 1), i
        Next i
Все ОК, но ХОТЕЛОСЬ бы в готовом словаре, причём обязательно БЕЗ ЦИКЛА получить кол-во ключей, удовлетворяющих условию (в примере дата должна быть сентябрьской). Пытался сделать так:
Код
ss = Application.CountIf(dicData.keys, "??.09.2022")
не выходит, ругаться на код не ругается, но значение ss становится типа массивом и значением каждого элемента Error 2015. Можно ли решить данный вопрос именно так, т.е. самое главное без цикла или нет? Если нет, ничего страшного, сейчас вопрос уже имеет решение.

Заранее спасибо всем откликнувшимся.
 
Считайте ss при создании словаря
Код
Set dicData = CreateObject("Scripting.Dictionary"): dicData.CompareMode = 1
    x = Range("A1:B" & Cells(Rows.Count, 2).End(xlUp).Row).Value
        For i = 1 To UBound(x)
            dicData.Add x(i, 1), i
            If x(i, 1) = "??. 09.2022" Then ss = ss + 1
        Next i
Изменено: Msi2102 - 23.10.2022 14:47:43
 
Да счетчик у меня и так стоит ниже по коду, но и за Ваш вариант, Msi2102, спасибо. Просто интересно: ведь формулой считается правильно, dicData.keys представляет собой массив (ведь так?), а почему тогда функция не хочет работать правильно? Причем ниже по коду эта функция, правда оперирующая с данными на листе, работает правильно
 
Цитата
OlegO написал:
а почему тогда функция не хочет работать правильно?
а где написано что она работает с массивом? Она работает с диапазоном.
По вопросам из тем форума, личку не читаю.
 
Цитата
OlegO написал:
dicData.keys представляет собой массив

А функция CountIf может иметь массив в качестве первого параметра?
Владимир
 
Цитата
написал:
где написано что она работает с массивом?
К стыду своему считал что это тождественные понятия, т.е. не выйдет мой каменный цветок? Ну что ж, оставим счетчик
 
Как вариант можно параллельно создать словарь, где посчитать количество всех дат по ключам год+месяц.
 
Да о чём тут, вообще, речь идет, даже если Application.CountIf заработает, то результат всегда будет 1, повторов ключа у Dictionary быть не может. Это нужно тогда использовать словарь словарей
Изменено: Msi2102 - 24.10.2022 09:11:40
 
OlegO, здравствуйте
Цитата
OlegO: причём обязательно БЕЗ ЦИКЛА
в который раз напоминаю, что внутри функций типа СЧЁТЕСЛИ цикл обязательно ЕСТЬ.
Смущает количество строк кода или такую домашку задали?

По вопросу: без циклов никак. Лучше, параллельно с основным словарём (в одном цикле, без дополнительного), создавать словарь с ключами "год-месяц" (как сказал Hugo) и сразу считать их количество: dYM(Key)=dYM(Key)+1. В таком случае, вы без цикла, в любой момент времени сможете узнать количество значений с заданным месяцем года.
Если же вы заранее, не знаете, какую арифметику нужно будет проводить, то тут ничего не поделаешь - чудес не бывает. Можете только создать все возможные словари расчётов, например, если памяти хватит. А так только циклы по необходимости. Чего вы их боитесь?)
Изменено: Jack Famous - 24.10.2022 10:00:07
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Если правильно понял, то возможно ТС ищет это
Код
Private Sub CommandButton1_Click()
    Set dicData = CreateObject("Scripting.Dictionary"): dicData.CompareMode = 1
    x = Range("A1:B" & Cells(Rows.Count, 2).End(xlUp).Row).Value
    For i = 1 To UBound(x)
        If Not dicData.exists(CDate(x(i, 1))) Then Set dicData(CDate(x(i, 1))) = CreateObject("Scripting.Dictionary")
        dicData(CDate(x(i, 1)))(dicData(CDate(x(i, 1))).Count) = x(i, 2)
    Next
    MsgBox "Количество 14.01.2021 - " & dicData(CDate("14.01.2021")).Count & Chr(13) & "Количество 03.03.2021 - " & dicData(CDate("03.03.2021")).Count
End Sub
Изменено: Msi2102 - 24.10.2022 10:44:19
 
Цитата
Msi2102 написал:
повторов ключа у Dictionary быть не может.
а если приглядеться? Вопрос то по подсчету по маске.

Цитата
Hugo написал:
где посчитать количество всех дат по ключам год+месяц.
Цитата
Jack Famous написал:
как сказал  Hugo
это хорошо когда срез известен и хочется посчитать в конкретном месяце или ... а когда на лету нужно срез сделать, такой своеобразный OLAP
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ: это хорошо когда срез известен и хочется посчитать в конкретном месяце или ... а когда на лету нужно срез сделать
Цитата
Jack Famous: Если же вы заранее, не знаете, какую арифметику нужно будет проводить, то тут ничего не поделаешь - чудес не бывает. Можете только создать все возможные словари расчётов, например, если памяти хватит. А так только циклы по необходимости
любые олапы требуют времени и, как правило, больше, чем цикл по массиву.

В любом случае, это уже не по теме. По теме
Цитата
OlegO: Функция CountIf для ключей словаря
не работает - нужно делать цикл по массиву/коллекции ключей или исходных данных. Вот и весь ответ  :)
Изменено: Jack Famous - 24.10.2022 14:33:30
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
А вот так если?
Код
ss = UBound(Filter(dicData.keys, ".09.2022")) + 1
Скажи мне, кудесник, любимец ба’гов...
 
_Boroda_, неплохо  8)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
_Boroda_ написал:
А вот так если?
Точно :)
Только теперь возникает вопрос, если будет повторение дат, например 01.09.2022 будет повторяться дважды, она должна считаться как одна дата или как две. Если как одна, тогда уж лучше заморочиться со словарями
Код
Private Sub CommandButton1_Click()
    Set dicData = CreateObject("Scripting.Dictionary"): dicData.CompareMode = 1
    x = Range("A1:B" & Cells(Rows.Count, 2).End(xlUp).Row).Value
    For i = 1 To UBound(x)
        If Not dicData.exists(Year(CDate(x(i, 1)))) Then Set dicData(Year(CDate(x(i, 1)))) = CreateObject("Scripting.Dictionary")
        If Not dicData(Year(CDate(x(i, 1)))).exists(Month(CDate(x(i, 1)))) Then Set dicData(Year(CDate(x(i, 1))))(Month(CDate(x(i, 1)))) = CreateObject("Scripting.Dictionary")
        If Not dicData(Year(CDate(x(i, 1))))(Month(CDate(x(i, 1)))).exists(Day(CDate(x(i, 1)))) Then Set dicData(Year(CDate(x(i, 1))))(Month(CDate(x(i, 1))))(Day(CDate(x(i, 1)))) = CreateObject("Scripting.Dictionary")
        dicData(Year(CDate(x(i, 1))))(Month(CDate(x(i, 1))))(Day(CDate(x(i, 1))))(dicData(Year(CDate(x(i, 1))))(Month(CDate(x(i, 1))))(Day(CDate(x(i, 1)))).Count) = CStr(x(i, 2))
    Next
    MsgBox "Количество дней в январе 2021 - " & dicData(2021)(1).Count & Chr(13) & _
           "Количество дней в марте 2021 - " & dicData(2021)(3).Count & Chr(13) & _
           "Количество дней в январе 2022 - " & dicData(2022)(1).Count & Chr(13) & _
           "Количество дней в марте 2022 - " & dicData(2022)(3).Count & Chr(13)
    MsgBox "Дни в марте 2021 - " & Chr(13) & Join(dicData(2021)(3).Keys, Chr(13))
End Sub
Изменено: Msi2102 - 24.10.2022 15:52:50
 
_Boroda_, аналог на Like чуть медленнее (не ожидал), зато спецфункция для подсчёта месяцев - в 2,5 раза быстрее
Код
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Огромная благодарность всем за продолжение темы, хотя весь сыр-бор был из-за попытки чуть оптимизировать свой код по своей собственной инициативе. НО за советы еще раз спасибо!
Страницы: 1
Наверх