Страницы: 1
RSS
Создавать массив или еще есть способ?
 
Добрый день.

Вопрос больше абстрактный.
Например есть таблица клиентов и их закупки за определенный период.
Но 1 клиент за этот период может совершить больше 1 покупки.

Не хочется создавать сводные таблицы и работать с ними.
Можно как-нибудь поместить эти данные в массив в уже просуммированном виде по клиенту?
 
Цитата
Вопрос больше абстрактный
Такой же ответ: можно)
 
В словарь тоже можно.
 
Цитата
Такой же ответ: можно)
А можно хотя бы алгоритм озвучить?

Абстрактный пример во вложении :) Но суть он дает понять.
И если предполагаемый размер массива будет 700т-900т значений, на сколько это будет быстро работать вообще ? может и не стоит даже делать?
 
Мой алгоритм (если не нужна выборка ещё и по заказам): все данные в массив, создаём коллекцию уникальных покупателей (клиентов), цикл по коллекции - вложенный цикл по массиву: если значение совпало - суммируем данные из четвёртого столбца.
Игорь сейчас предложит вариант со словарём. Наверное, будет быстрее))
 
Быстрей будет сводной :)
Я сам - дурнее всякого примера! ...
 
Не, практически код писать почему-то не хочется... :)
А готовый похожий код сходу не нашёл. Но они точно есть на форуме, много.
Скажу про скорость - заполнение словаря на миллион записей занимало около 30 секунд, с коллекцией быстрее, но как к коллекции прикрутить номер строки - не знаю.
А с словарём с массивом так - заносим в словарь ключ и номер строки массива, в котором собираем суммы (можно использовать тот же исходный массив).
При повторе ключа извлекаем номер строки и дополняем массив.
В конце выгрузка собранного куда угодно.
 
А я поддержу Сергея: сводная, однозначно. Если важна именно скорость решения.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Дмитрий, а как сводная с миллионом справится? Кажется были проблемы у людей...

Ну вот, не хотел ведь писать... Написал - оказывается что-то понял не так, или пример не такой, или объяснения...
Там в примере нет повторов!

Код
Option Explicit

Sub tt()
    Dim a(), t$, tt&, x&, i&, ii&

    a = [a1].CurrentRegion.Value
    ii = 1
    With CreateObject("Scripting.Dictionary"): .comparemode = 1
        For i = 2 To UBound(a)
            t = Trim(a(i, 1)) & "|" & Trim(a(i, 2))
            If .exists(t) Then
                tt = .Item(t)
                a(tt, 3) = a(tt, 3) + a(i, 3)
                a(tt, 4) = a(tt, 4) + a(i, 4)
            Else
                ii = ii + 1
                .Item(t) = ii
                For x = 1 To UBound(a, 2): a(ii, x) = a(i, x): Next
            End If
        Next
    End With

    [h1].Resize(ii, UBound(a, 2)) = a
End Sub

И "Отгружено" пишется так, а не так, как на листе! :)
 
Цитата
Не, практически код писать почему-то не хочется...   :)
Писать ничего не надо, так не интересно получается :)

Походу со сводной не только быстрее, но и в разы проще :)
Цитата
А с словарём с массивом так - заносим в словарь ключ и номер строки массива, в котором собираем суммы (можно использовать тот же исходный массив).
Я не очень понимаю где в словаре хранить суммы по заказам, ведь синтакс  - object.Add key, item
Или я что-то не так понимаю?
И что касается просто массива, то не получится его объявить как диапазон, надо циклом заполнять? Я правильно понимаю?

А если например объявить массив через диапазон и потом циклом прогонять по клиенту и суммировать, это не будет проще/быстрее?

Вообще основная мысль это подключать внешний файл без открытия и обновлять данные в работающей книге, поэтому сводную ой как не хочется делать :)
 
В словаре вот в item и хранить. Если сумма одна. Если их много - тогда храним индекс массива, а суммы в массиве.
Ну а подключать без  открытия - тогда юзайте SQL, есть тут спец RDmitry - может заглянет :)
Хотя можно и мой код использовать, открывая файл с getobject() - тоже будет быстро.
 
Да, в коде выше, если данные без косяков - можно убрать Trim() - будет бегать быстрее.
 
Сводная в 2010 не имеет проблем с количеством строк. Да и в 2007, насколько помню нет каких-то ограничений, которые сильно помешают в данном случае.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
все данные в массив, создаём коллекцию уникальных покупателей (клиентов), цикл по коллекции - вложенный цикл по массиву: если значение совпало - суммируем данные из четвёртого столбца.

Только раза с третьего дошло :)
Только так и не дошло в каком месте суммировать ((( точнее куда писать данные, обновлять массив или сразу куда-то?
 
лучше все таки сводными, тем более с такими размерами
Живи и дай жить..
 
" в каком месте суммировать"
Код
If .exists(t) Then
                tt = .Item(t)
                a(tt, 3) = a(tt, 3) + a(i, 3)
                a(tt, 4) = a(tt, 4) + a(i, 4)

Плюсики только в этом месте :)
Изменено: Hugo - 24.10.2013 14:28:56
 
А вот ТС нам и напишет, что будет в итоге лучше :)
Может быть...
 
Цитата
оказывается что-то понял не так, или пример не такой, или объяснения...
Меня интересовала только статистика и суммирование по клиенту, заказ добавлять не надо было :)

Ещё я не очень понял по поводу словаря, я думал он может содержать только 1 ключевое поле и 1 поле, а тут выходит можно много добавлять? :)

Я так понимаю поля указываются через запятую и их может быть много, да ?
Цитата
Dim a(), t$, tt&, x&, i&, ii&
 
Наберите в поисковике scripting.dictionary - проще будет.
Словарь может содержать коллекцию уникальных ключей. Для каждого ключа - значение. вот значения можно получать и изменять по ходу выполнения на основании ключа.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
В данном случае в словаре уникальные ключи (как всегда) и к каждому ключу одно значение - индекс массива (номер строки).
Ну а массив можем делать "в ширину" сколько хватит памяти. Хотя в данном случае использую тот же исходный массив - это должно здорово сэкономить память в случае миллиона строк  :)  
Но значением в словаре может быть почти что угодно - число, строка, массив, коллекция, другой словарь, объект... Не знаю, вероятно есть что-то, что не может быть значением - но не знаю что  :)  

По задаче - если заказы не нужны, тогда код будет такой:

Код
Option Explicit

Sub tt()
    Dim a(), t$, tt&, x&, i&, ii&

    a = [a1].CurrentRegion.Value 'массив данных
    ii = 1: a(1, 2) = a(1, 3): a(1, 3) = a(1, 4) 'чуть двигаем шапку - один столбец не нужен
    With CreateObject("Scripting.Dictionary"): .comparemode = 1
        For i = 2 To UBound(a) 'шапку не анализируем
            t = Trim(a(i, 1)) 'ключ
            If .exists(t) Then 'если есть ключ
                tt = .Item(t) 'извлекаем индекс
                a(tt, 2) = a(tt, 2) + a(i, 3) 'дополняем массив
                a(tt, 3) = a(tt, 3) + a(i, 4)
            Else 'если ключа нет
                ii = ii + 1: .Item(t) = ii 'увеличиваем/запоминаем индекс
                a(ii, 1) = a(i, 1) 'заполняем массив исходными данными
                For x = 2 To 3: a(ii, x) = a(i, x + 1): Next
            End If
        Next
    End With

    [h1].Resize(ii, 3) = a 'выгружаем результат
End Sub

А вот это:
Dim a(), t$, tt&, x&, i&, ii&
просто переменные - один массив, строка-ключ и счётчики строк/столбцов.

P.S. Причём tt или x можно сократить - можно использовать одну переменную, да и в общем от x  и так толку уже мало :)
Изменено: Hugo - 24.10.2013 16:32:30
 
Цитата
Только так и не дошло в каком месте суммировать ((( точнее куда писать данные, обновлять массив или сразу куда-то?
Во второй (маленький) массив))
 
Большое спасибо, получилось подрубить.
Пока опробовал на маленьком массиве, всего 5т время выполнения около 2с, только почему-то сюда не включается время на подключение файла, ну субъективно это не 2с, а около 10, но терпимо.

Но у меня возникла проблема при сравнении рабочего файла с созданным массовом.
Решено было в итоге сравнивать по номеру заказа, а он естественно числовой.
Все бы хорошо, но по какой-то причине в массиве номер заказа указан в двойных кавычках и при сравнении естественно не находится. Пробовал обрезать через replace(target, Chr(34),""), не обрезается :(

100% есть какой-нибудь простой способ преобразовать данные в массиве и убрать эти кавычки.
 
1. "В массиве в кавычках" - это где? Не вижу такого в примере.
2. "по номеру заказа, а он естественно числовой" - вообще-то довольно часто такие номера бывают типа "AB15867" или "000015", но не суть - Вы же не собраетесь их складывать/умножать?
Т.е. правильнее все номера иметь в текстовом виде, так их  и сравнивать.
И вероятно эти кавычки только в окне Locals в массиве, что и говорит о том, что эти данные типа string.
А появляются они у этих "чисел" тут:
t = Trim(a(i, 1)) 'ключ
Если есть уверенность, что никаких пробелов по концам никогда не будет, и что это всегда и всюду 100% будут числа - Trim() можно убрать, так даже быстрее будет работать. Но ненадёжнее :(
Страницы: 1
Наверх