Сбор статистики

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Ruslan Demidow
Мужчина!
Мужчина!
Аватара пользователя
 
Сообщения: 987
Зарегистрирован: 25.03.2004 (Чт) 13:39
Откуда: N.Novgorod

Сбор статистики

Сообщение Ruslan Demidow » 12.08.2004 (Чт) 15:55

Вот задумался я о сборе статистики.
Имеется тип записи
Код: Выделить всё
Type SabjRecord
       FromName as String 'имя отправителя
       ToName as String 'имя получателя
       Name as String 'тема письма
       DateTime as String 'время и дата создания сообщения
       FromAdress as string
End Type


Имеется так же массив таких записей arrSabj().
Хочется организовать статистику по конференции: наибольшее количество постов, наибольшее количество полученных сообщений, и отдельно по каждому отправителю количество отправленных и количество полученных.
Я отобрал уникальные имена через коллекцию. После этого загнал элементы коллекции в сортированный список. После этого из сортированного списка загнал все имена в массив arrNames(), который содержит записи типа
Код: Выделить всё
Type tNames
    Name as String
    PostCount as Integer
    ReplyCount as Integer
End Type

После этого я пробегаюсь по массиву сообщений (arrSabj) и для каждого сообщения ищу в массиве arrNames() имя соответствующее текущему отправителю. Если нахожу, то увеличиваю значение arrNames().PostCount на 1.
При количестве сообщений до 3 000 - скорость выполнения ещё терпима. Но при количестве сообщений ближе к 9 000 - вышеописанная операция занимает примерно 38 сек. - что меня совсем не радует. :(
Скорость сильно зависит от количества сообщений и количества подписчиков конференции. :(

Подскажите плиз структуру алгоритма для построения статистики или дайте пример, плиз.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 12.08.2004 (Чт) 16:20

Даём.
БД, SQL.
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Re: Сбор статистики

Сообщение tyomitch » 12.08.2004 (Чт) 20:07

Ruslan Demidow писал(а):После этого я пробегаюсь по массиву сообщений (arrSabj) и для каждого сообщения ищу в массиве arrNames() имя соответствующее текущему отправителю. Если нахожу, то увеличиваю значение arrNames().PostCount на 1.

Я бы посоветовал вместо массива arrNames() завести коллекцию, где ключ - имя, и не из структур, а из ссылок на объекты.
Должно стать гораздо быстрее.

А тем, кто предлагает заместо сортировки массива загонять его в базу и потом читать обратно - наше фи.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 12.08.2004 (Чт) 20:18

О нет, что вы! Амикошонство не в нашем духе, мы токмо за продвинутость и скороссть ратуем :)
Мы не предлагаем в базу и обратно, мы предлагаем вообще всю систему нафиг переделать, чтобы это изначально была база.
А коллекция работает медленнее массива, это веками изведано :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 12.08.2004 (Чт) 21:08

GSerg писал(а):О нет, что вы! Амикошонство не в нашем духе, мы токмо за продвинутость и скороссть ратуем :)
Мы не предлагаем в базу и обратно, мы предлагаем вообще всю систему нафиг переделать, чтобы это изначально была база.
А коллекция работает медленнее массива, это веками изведано :)

Во-первых, это я не про тебя :-D
Просто вспомнились мне люди, которые на вопрос "как отсортировать массив" отвечали "загонять его в базу и потом читать обратно", или даже "создать невидимый отсортированный ListBox, загонять туда и потом читать обратно". Вспомнились именно потому, что решать существующие проблемы созданием новых (в данном случае, прикручивать базу) - нерационально.

Изначально база здесь конечно была бы лучше всего, но изначально её уже нет :-(, а переделывать всё нафиг, чтоб легче сортировались массивы - это неадекватно.

Коллекция работает медленнее массива при доступе по индексу. А у Руслана поиск по ключу, ещё и линейный, скорее всего. Поиск в коллекции точно уж быстрее, чем в массиве.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 13.08.2004 (Пт) 8:49

А я бы советовал все-же остановится на массивах. Только к ним в комплект снарядить индексы (для быстрого поиска). Может именно поиск и будет чуть медленнее (бинарный поиск на низком уровне все-равно не переплюнуть), но гораздо гибче. Вот только с индексированием придется чуть повозиться :)
Lasciate ogni speranza, voi ch'entrate.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 13.08.2004 (Пт) 8:59

alibek писал(а):А я бы советовал все-же остановится на массивах. Только к ним в комплект снарядить индексы (для быстрого поиска). Может именно поиск и будет чуть медленнее (бинарный поиск на низком уровне все-равно не переплюнуть), но гораздо гибче. Вот только с индексированием придется чуть повозиться :)

В коллекции не бинарный поиск, а хэш-таблица. Бинарный поиск в массиве строк неизбежно будет тормозить из-за того, что сравнивать строки - очень долго.
Чем здесь лучше массивы-то? Непримиримая ненависть к коллекциям?
И зачем возиться с индексированием, если коллекция уже есть?

Ruslan Demidow
Мужчина!
Мужчина!
Аватара пользователя
 
Сообщения: 987
Зарегистрирован: 25.03.2004 (Чт) 13:39
Откуда: N.Novgorod

Сообщение Ruslan Demidow » 13.08.2004 (Пт) 10:51

GSerg писал(а):Даём.
БД, SQL.

Для меня новО и пока кажется громоздким... Так что думаю не пойдёт..

Ruslan Demidow
Мужчина!
Мужчина!
Аватара пользователя
 
Сообщения: 987
Зарегистрирован: 25.03.2004 (Чт) 13:39
Откуда: N.Novgorod

Re: Сбор статистики

Сообщение Ruslan Demidow » 13.08.2004 (Пт) 10:53

tyomitch писал(а):
Ruslan Demidow писал(а):После этого я пробегаюсь по массиву сообщений (arrSabj) и для каждого сообщения ищу в массиве arrNames() имя соответствующее текущему отправителю. Если нахожу, то увеличиваю значение arrNames().PostCount на 1.

Я бы посоветовал вместо массива arrNames() завести коллекцию, где ключ - имя, и не из структур, а из ссылок на объекты.
Должно стать гораздо быстрее.

А тем, кто предлагает заместо сортировки массива загонять его в базу и потом читать обратно - наше фи.

Окей. Я кажется понял твою мысль. Попробую.

Ruslan Demidow
Мужчина!
Мужчина!
Аватара пользователя
 
Сообщения: 987
Зарегистрирован: 25.03.2004 (Чт) 13:39
Откуда: N.Novgorod

Сообщение Ruslan Demidow » 13.08.2004 (Пт) 11:01

tyomitch писал(а):Изначально база здесь конечно была бы лучше всего, но изначально её уже нет :-(, а переделывать всё нафиг, чтоб легче сортировались массивы - это неадекватно.

Я тоже так подумал. У меня почти вся обработка данных построена на массивах. Массив конференций, массив заголовков сообщений и т.п.
Переделывать на коллекции - переделывать с нуля.

Коллекция работает медленнее массива при доступе по индексу. А у Руслана поиск по ключу, ещё и линейный, скорее всего.

Линейный это как? (простите мою чайниковость.. :oops: ) Я обращаюсь к элементам коллекции по ключу.

Поиск в коллекции точно уж быстрее, чем в массиве.

Я хотел сделать сначала имена в массиве, но как подумал, что буду перебирать для каждого сообщения все, предположим, 300 элементов массива для поиска нужного имени - решил - не стоит.
Коллекция в этом случае хороша, но она не позволяет хранитть пользовательские типы данных. :(

Ruslan Demidow
Мужчина!
Мужчина!
Аватара пользователя
 
Сообщения: 987
Зарегистрирован: 25.03.2004 (Чт) 13:39
Откуда: N.Novgorod

Сообщение Ruslan Demidow » 13.08.2004 (Пт) 11:02

alibek писал(а):А я бы советовал все-же остановится на массивах. Только к ним в комплект снарядить индексы (для быстрого поиска). Может именно поиск и будет чуть медленнее (бинарный поиск на низком уровне все-равно не переплюнуть), но гораздо гибче. Вот только с индексированием придется чуть повозиться :)

Как это, снарядить индексы? Массив же уже с индексированными элементами... Или я чего-то не понял?

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 13.08.2004 (Пт) 11:57

Коллекция позволяет искать только по ключу, индексные же массивы придадут больше гибкости.
А коллекции я и правда не люблю :)

А индексированный массив - я имею ввиду к массиву aData() создать вспомогательный массивы idxName(), idxAddress(), в которых осуществено индексирование по имени, адресу.
Lasciate ogni speranza, voi ch'entrate.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 13.08.2004 (Пт) 12:16

Ruslan Demidow писал(а):
Коллекция работает медленнее массива при доступе по индексу. А у Руслана поиск по ключу, ещё и линейный, скорее всего.

Линейный это как? (простите мою чайниковость.. :oops: ) Я обращаюсь к элементам коллекции по ключу.


Ruslan Demidow писал(а):После этого я пробегаюсь по массиву сообщений (arrSabj) и для каждого сообщения ищу в массиве arrNames() имя соответствующее текущему отправителю.
Как ищешь массиве arrNames() имя? Циклом от нижней границы до верхней? Тогда линейно.

Ruslan Demidow писал(а):
Поиск в коллекции точно уж быстрее, чем в массиве.

Я хотел сделать сначала имена в массиве, но как подумал, что буду перебирать для каждого сообщения все, предположим, 300 элементов массива для поиска нужного имени - решил - не стоит.
Коллекция в этом случае хороша, но она не позволяет хранитть пользовательские типы данных. :(

tyomitch писал(а):Я бы посоветовал вместо массива arrNames() завести коллекцию, где ключ - имя, и не из структур, а из ссылок на объекты.

Я и предлагал тебе завести класс вместо пользовательского типа. Тогда можно будет изменять его поля, не удаляя и перекладывая в коллекцию.
Или принципиально, чтобы это был именно UDT?

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 13.08.2004 (Пт) 12:24

alibek писал(а):Коллекция позволяет искать только по ключу, индексные же массивы придадут больше гибкости.
А коллекции я и правда не люблю :)

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

А коллекции я люблю :-)
Сам когда-то писал на Делфи Продвинутые Коллекции - например, позволяющие хранить несколько элементов под одним ключом, соответственно, свойство Item было типа Variant(). Поняв, сколько труда вложено в стандарную VBA.Collection, я её теперь очень люблю :-)

Ruslan Demidow
Мужчина!
Мужчина!
Аватара пользователя
 
Сообщения: 987
Зарегистрирован: 25.03.2004 (Чт) 13:39
Откуда: N.Novgorod

Сообщение Ruslan Demidow » 13.08.2004 (Пт) 12:39

tyomitch писал(а):
Ruslan Demidow писал(а):После этого я пробегаюсь по массиву сообщений (arrSabj) и для каждого сообщения ищу в массиве arrNames() имя соответствующее текущему отправителю.

Как ищешь массиве arrNames() имя? Циклом от нижней границы до верхней? Тогда линейно.

Ясно. Я так и делал. После нахождения нужного Exit For.

Ruslan Demidow писал(а):
Поиск в коллекции точно уж быстрее, чем в массиве.

Я хотел сделать сначала имена в массиве, но как подумал, что буду перебирать для каждого сообщения все, предположим, 300 элементов массива для поиска нужного имени - решил - не стоит.
Коллекция в этом случае хороша, но она не позволяет хранитть пользовательские типы данных. :(

tyomitch писал(а):Я бы посоветовал вместо массива arrNames() завести коллекцию, где ключ - имя, и не из структур, а из ссылок на объекты.

Я и предлагал тебе завести класс вместо пользовательского типа. Тогда можно будет изменять его поля, не удаляя и перекладывая в коллекцию.
Или принципиально, чтобы это был именно UDT?

Нет не принципиально. Но я не пойму (чайник ещё :) ), как можно в классе хранить данные, много данных?
Но я уже решил эту задачу через коллекцию.
Код: Выделить всё
Private Sub GetAreaStatistic()
    Dim NamesCol As New Collection
    Dim sName As String, MaxName As String, MaxPost As Integer
    Dim PostCount As Integer
    Dim i As Long, u As Integer, s As String
    sbrStatus.Panels("Events").Text = "Сбор данных для статистики ..."
    With frmProgress
        .lblTitle = "Сбор данных для статистики"
        .LoadProgressBar.Min = 0
        .LoadProgressBar.Max = UBound(arrSabj)
        .Show
        .Refresh
    End With
   
    StatisticNamesList.Clear
    Set NamesCol = Nothing
    PostCount = 0
    MaxPost = 0
    MaxName = ""
   
    For i = LBound(arrSabj) To UBound(arrSabj)
        frmProgress.LoadProgressBar.Value = i
        sName = Trim$(ConvOemToAnsi(arrSabj(i).FromName))
        If Not bExistName(sName, NamesCol) Then
            NamesCol.Add 0, sName
            StatisticNamesList.AddItem sName
        End If
        PostCount = NamesCol(sName)
        NamesCol.Remove (sName)
        NamesCol.Add PostCount + 1, sName
        If MaxPost < NamesCol(sName) Then
            MaxName = sName
            MaxPost = NamesCol(sName)
        End If
    Next i
    frmProgress.Hide
   
    sbrStatus.Panels("Events").Text = "Вывод данных статистики..."
    s = ""
    With StatisticNamesList
       For u = 1 To StatisticNamesList.ListCount
            sName = Trim$(StatisticNamesList.List(u))
            If Len(sName) > 0 Then
                s = s & sName & vbCrLf
                s = s & "Сообщений:" & NamesCol(sName) & vbCrLf
                s = s & "--------------------------------------------" & vbCrLf
            End If
        Next u
    End With
   
    With MsgTextBox
            s = vbCrLf & "Список авторов конференции " & "(" & NamesCol.Count & ")" & _
            vbCrLf & "====================================" & vbCrLf & _
            "Максимальное количество отправленных сообщений: " & _
            MaxName & " (" & MaxPost & ")" & vbCrLf & _
            "===============================" & vbCrLf & s
            .SelStart = Len(.Text)
            .SelText = s
    End With
    SendMessage sbrStatus.hwnd, WM_SETREDRAW, Abs(True), 0&
    sbrStatus.Panels("Events").Text = ""
End Sub

В роли подопытного кролика была конференция RU.VISUAL.BASIC с общим количеством сообщений 9 500 с копейками. И если раньше сбор статистики занимал время до 40 сек. То теперь не больше 5-7 секунд.
Вот результат работы этой процедуры:

Код: Выделить всё
Конференция: RU.VISUAL.BASIC
Описание: Программирование в Visual Basic
Дата создания: (Сб) 03 авг 2002 19:24:30
Группа: FIDO
===========================================
Количество сообщений: 9504
Количество прочитанных: 9504
Количество непрочитанных: 0
===========================================
АКА для этой области: 2:5015/112.35
UpLink для этой области: 2:5015/112
===========================================
Имя файла заголовков: 00000043.hdr
===========================================

Список авторов конференции (686)
===================================================
Максимальное количество отправленных сообщений: A. Skrobov (849)
========================================================
A. Skrobov
Сообщений:849
--------------------------------------------
A.Skrobov
Сообщений:3
--------------------------------------------
Admin VBNet \(SHatrykin Ivan\)
Сообщений:1
--------------------------------------------
AKM
Сообщений:1
--------------------------------------------
Albert Einstein
Сообщений:34
--------------------------------------------


С чем я тебя и поздравляю! :lol:

Всем ответившим спасибо БОЛЬШОЕ!!! Топик можно считать закрытым. :)

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 13.08.2004 (Пт) 15:15

Ruslan Demidow писал(а):
tyomitch писал(а):Я и предлагал тебе завести класс вместо пользовательского типа. Тогда можно будет изменять его поля, не удаляя и перекладывая в коллекцию.
Или принципиально, чтобы это был именно UDT?

Нет не принципиально. Но я не пойму (чайник ещё :) ), как можно в классе хранить данные, много данных?
Но я уже решил эту задачу через коллекцию.

Всё-таки попытаюсь объяснить (добавление/удаление элементов в коллекции - медленная операция, и если от неё избавиться, должно стать ещё быстрее):
Создаёшь класс clsNames с тремя строчками:
Код: Выделить всё
Public Name As String
Public PostCount As Integer
Public ReplyCount As Integer

Вместо строчки NamesCol.Add 0, sName пишешь:
Код: Выделить всё
Dim NewItem As clsNames: Set NewItem = New clsNames
NewItem.Name = sName
NamesCol.Add NewItem, sName

Вместо строчек:
Код: Выделить всё
PostCount = NamesCol(sName)
NamesCol.Remove (sName)
NamesCol.Add PostCount + 1, sName
If MaxPost < NamesCol(sName) Then
    MaxName = sName
    MaxPost = NamesCol(sName)
End If

пишешь:
Код: Выделить всё
With NamesCol(sName)
    .PostCount = .PostCount + 1
    If MaxPost < .PostCount Then
        MaxName = .Name
        MaxPost = .PostCount
    End If
End With

Должно стать ещё быстрее - проверь.

Ruslan Demidow
Мужчина!
Мужчина!
Аватара пользователя
 
Сообщения: 987
Зарегистрирован: 25.03.2004 (Чт) 13:39
Откуда: N.Novgorod

Сообщение Ruslan Demidow » 13.08.2004 (Пт) 21:44

Ага, понял.
Спасибо за ликбез. Так и сделаю.
Это даже удобнее, чем через коллекцию. :)
Проверю обязательно.


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Google-бот и гости: 15

    TopList