Форум программистов, компьютерный форум, киберфорум
VBA
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.65/141: Рейтинг темы: голосов - 141, средняя оценка - 4.65
0 / 0 / 0
Регистрация: 16.03.2013
Сообщений: 54
1

Поиск и выделение в таблице по нескольким параметрам

03.04.2013, 01:53. Показов 28970. Ответов 75
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Ночи доброй форумчане!
возник следующий вопрос:

есть таблица(размерность может быть как увеличена, так и уменьшена)
можно ли вывести на экран менюшку в котороый можно будет задавать несколько параметров поиска?



к примеру в таблице надо найти все ячейки в которых встречаются сразу все эти критерии( П, Г, 234, МЗН)
кол-во параметров может варьироваться от 1го до ++
вбивать параметры нужно ручками в специальном окошке(менюшке), (и в любом порядке)

нужные ячейки будут подсвечиваться цветом к примеру "vbGreen"
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
03.04.2013, 01:53
Ответы с готовыми решениями:

Как можно найти строки в таблице по нескольким параметрам одного столбца?
Как можно найти строки в таблице по нескольким параметрам одного столбца? Допустим у нас есть:...

Поиск по нескольким параметрам?
Вот поиск по фамилии - RS.Find 'fam Like ' & ''' & strFind & ''' adSearchForward А как его...

Поиск по нескольким параметрам
Есть таблица с названием one a1 a2 a3 a4 0 1 2 3 А так же таблица two в которой b1 b2 b3...

поиск по нескольким параметрам
Здраствуйте. Делаю на диплом базу даных ноутбуков!!! Возникла проблема с поиском. Хочу зделать...

75
4377 / 661 / 36
Регистрация: 17.01.2010
Сообщений: 2,134
03.04.2013, 23:43 41
Author24 — интернет-сервис помощи студентам
To Hugo. Теперь самая большая проблема для RewCrew - сохранить возможность сравнения в ТАЙНЕ!!! от того человека, который в эту таблицу заносит данные. Нет, я ему не завидую.
1
0 / 0 / 0
Регистрация: 16.03.2013
Сообщений: 54
03.04.2013, 23:48  [ТС] 42
Igor_Tr, теперь все стало понятно)

Hugo121, ну здесь проблем не будет, т.к. условия только кириллицей и только в верхнем регистре будут записаны. Но на всякий случай возьму на заметку.

Добавлено через 3 минуты
Цитата Сообщение от Igor_Tr Посмотреть сообщение
Теперь самая большая проблема для RewCrew - сохранить возможность сравнения в ТАЙНЕ!!! от того человека, который в эту таблицу заносит данные. Нет, я ему не завидую.
полностью согласен с вами
0
6922 / 2832 / 543
Регистрация: 19.10.2012
Сообщений: 8,645
03.04.2013, 23:49 43
Если в верхнем - UCase()
В любом случае если запрашиваете в inputbox - не лишним будет привести к одному регистру, да и транслитерировать тоже. И откинуть лишние пробелы application.trim'ом (обязательно!)

Добавлено через 57 секунд
Если будете заводить сами - тогда можно этого не делать
2
0 / 0 / 0
Регистрация: 16.03.2013
Сообщений: 54
03.04.2013, 23:51  [ТС] 44
Цитата Сообщение от Hugo121 Посмотреть сообщение
Если в верхнем - UCase()
В любом случае если запрашиваете в inputbox - не лишним будет привести к одному регистру, да и транслитерировать тоже. И откинуть лишние пробелы application.trim'ом (обязательно!)
учту, спасибо!
0
6922 / 2832 / 543
Регистрация: 19.10.2012
Сообщений: 8,645
03.04.2013, 23:58 45
Нет, если проверяете работу другого - тогда эти трансформации как раз не нужны. Сами ввели как нужно - нашли правильно введённые. Если там напутано - значит напутано...
1
4377 / 661 / 36
Регистрация: 17.01.2010
Сообщений: 2,134
04.04.2013, 12:34 46
To_RewCrew. Здравствуйте. Решил сохранить для себя - на всякий случай. Просмотрел. Обратите внимание на ячейку "c13" ("П,234, МЗН"). Пропущен пробел! Работа не корректна! Нужно учитывать. Я рекомендую, с учетом подсказок Hugo121, заменить вверху mstr = StrConv(mstr, vbUpperCase) на mstr = LCase(mstr), и ниже, многострадальный фрагмент
If Len(currCell) Then ' верхний ориентир
newstr = StrConv(currCell.Value, vbUpperCase)
rrCEL = Split(Application.Trim(newstr), ", ")
For i = LBound(rrSTR) To UBound(rrSTR) ' нижний ориентир
на
Visual Basic
1
2
3
4
If Len(currCell) Then
   newstr = Application.Trim(Replace(currCell.Value, ",", ", ", 1))
   rrCEL = Split(Application.Trim(LCase(newstr)), ", ")
      For i = LBound(rrSTR) To UBound(rrSTR)
Теперь будет реагировать и на это. Богатая фантазия у Вашего напарника!!! При написании si-fi романов - незаменимое качество. Удачи!
1
0 / 0 / 0
Регистрация: 16.03.2013
Сообщений: 54
05.04.2013, 00:21  [ТС] 47
Igor_Tr, вот это да)
спасибо)
0
4377 / 661 / 36
Регистрация: 17.01.2010
Сообщений: 2,134
05.04.2013, 00:56 48
Здрасьте! Не совсем. Не знаю структуру Вашего листа и размеры. Судя по примеру - куча пустых ячеек в разбросе. И листинг их тоже проверяет, хоть и на лету. Будет время для себя - посижу над этим примером. Интересный. Но когда это будет - не знаю. Поэтому Вам подскажу. Вместо Set mRng = .usedrange.value нужно применить Set mRng = .UsedRange.SpecialCells(xlCellTypeConstants). Тогда будут проверяться только ячейки с значениями. И тут еще можно конкретизировать, но нужно точно знать Ваши условия, например, могут быть ячейки только с числами, или нет? Если есть, тогда нужно проверять, или нет. Другими словами - все это еще можна оптимизировать, ведь все было на лету. Пробуйте. У меня теперь руки не доходять. Только не подумайте - не бокалами заняты! Удачи.
0
4377 / 661 / 36
Регистрация: 17.01.2010
Сообщений: 2,134
07.04.2013, 22:05 49
Здравствуйте. Было сегодня время. Ну вот, такой результат. Я размножил Ваш пример до 2496 строк. Запустил - время до последних изменений - 36 секунд. Это много. С последними изменениями, время - 20 секунд. Как сделать быстрее - уже не знаю. Может здесь кто-то подправит, или подскажет, что применить. Но тем не меньше, если у Вас очень много данных, то эфект, конечно, будет. Все удачи.
Вложения
Тип файла: rar V_End_поиск_по_критериям.rar (35.1 Кб, 37 просмотров)
0
6922 / 2832 / 543
Регистрация: 19.10.2012
Сообщений: 8,645
07.04.2013, 22:51 50
Может я не вполне понял задачу... Но так быстрее - у меня в чуть более секунды укладывается:
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Sub tt()
    Dim cc As Range, odict As Object, el, flag As Boolean
    Dim dblResTime As Double
    Dim stTime As Date
    Dim mstr$
 
    Set odict = CreateObject("scripting.dictionary")
    odict.comparemode = 1
 
    mstr = InputBox("Занесіть критерії для пошуку в комірках " & _
                    Chr(13) & Chr(13) & "Rem. Регістр теж не має значення." & _
                    Chr(13) & Chr(13) & "наприклад :" & _
                    Chr(13) & Chr(13) & "П     г     234     МзН" & _
                    Chr(13) & Chr(13) & _
                    "(К-сть прогалин також значення не мають!)", , "П г 234 МзН")
    stTime = Timer
 
    Application.ScreenUpdating = False
 
    ActiveSheet.Cells.Interior.ColorIndex = xlNone
 
    For Each cc In ActiveSheet.UsedRange.Cells
        flag = True
        odict.RemoveAll
        For Each el In Split(Replace(cc.Value, ",", " "))
            odict.Item(el) = 0&
        Next
        For Each el In Split(mstr)
            If Not odict.exists(el) Then flag = False
        Next
        If flag Then cc.Interior.Color = vbRed
    Next
    Application.ScreenUpdating = True
 
    dblResTime = Format(Timer - stTime, "#0.00")
    MsgBox "Час   виконання   -   " & dblResTime
 
End Sub
Файл тот, что выше - V_End_поиск_по_критериям.rar

Добавлено через 4 минуты
Извиняюсь, не прочитал сворованный текст - у меня на запятые не рассчитано (исправил)
Но можно добавить.
И ещё нужно добавить выход из макроса, если инпутбокс закрыли отменой или крестом. Или ничего не завели.
1
4377 / 661 / 36
Регистрация: 17.01.2010
Сообщений: 2,134
07.04.2013, 23:34 51
To Hugo. Здравствуйте. Там, кратко, история такая. Человеку нужно найти набор (не комбинацию!!!) критериев. Тоесть, в ячейках раскидано всякое, по разному и много, и задаются для поиска критерии тоже наобум. В ячейке С100 может быть " А, П, 789, ввф, ...., Весна красивая". Он задает критерии "ввф, А, Весна". Нужно найти все ячейки и закрасить, где эти все критерии живут, не зависимо от наличия в тех ячейках других значений. Логики занесения данных нет, соответсвенно логики в задании параметров для поиска быть не может.
У меня есть что-то подобное (слава Богу, больше упорядоченное), только руки не доходили. Например, шифры расценок иногда записываються с определенными идентификаторами, такими как & ("применительно"). Вот меня и заинтересовало.

Добавлено через 10 минут
To Hugo. Вы меня убили. Наповал. Я НЕДОДУМАЛСЯ!!! ПРИМЕНИТЬ!!! СЛОВАРЬ!!! для содержимого ячейки!!!
Время - 3 секунды!!!. Спасибо. Все равно время не даром. Лучьше ошибаться, чем ничего...
0
6922 / 2832 / 543
Регистрация: 19.10.2012
Сообщений: 8,645
07.04.2013, 23:53 52
Перечитал код Поиск и выделение в таблице по нескольким параметрам (всёж 4 дня прошло, забылось) - там запятые тоже обрабатываются, т.е. они могут быть как разделители слов.
Ну а словарь не обязательно использовать, главное это флаг!
Просто со словарём меньше кода.
А задачу значит я понял правильно, так и делаю - проверяю каждую ячейку на наличие всех слов-критериев.
0
4377 / 661 / 36
Регистрация: 17.01.2010
Сообщений: 2,134
08.04.2013, 00:04 53
И раз уже такое. Где-то у нас в разговоре проскакивало насчет применения в качестве Item словаря - 0&. Прогнал на этом примере - хоть немного, но действительно быстрее
odict.Item(el) = 0& -1.43 сек.
odict.Item(el) = el - 1.45 сек.
А теперь не пойму, почему первая прогонка показала 3 сек.?
Еще раз спасибо.

Добавлено через 8 минут
Ну а словарь не обязательно использовать, главное это флаг!
Вот с флагом - все как раз и понятно. А что еще можно? Что б аналогично быстро. Мне тут нужно было для себя в некоторых местах Regular Expressions. Пока делал, в голове крутилось как к этому примеру привинтить. Но там у меня тоже получается цикл, от которого нужно уйти.
0
6922 / 2832 / 543
Регистрация: 19.10.2012
Сообщений: 8,645
08.04.2013, 00:16 54
0& - это 0 типа Long, что вроде как быстрее обрабатывается.
А вместо словаря можно каждое слово-критерий сравнить с каждым словом из очередной ячейки. т.е. split в массив, и цикл в цикле перебираем.
С регулярками я пока не дружу... хотя нужно бы освоить... Так иногда по примерам использую, но все их "вкусности" пока не прочувствовал.
0
4377 / 661 / 36
Регистрация: 17.01.2010
Сообщений: 2,134
08.04.2013, 00:49 55
т.е. split в массив, и цикл в цикле перебираем.
Что-то сомнительно, и очень, что время будет хотя бы такое-же. А RegExp использую тоже редко. И теперь смотрю - и удивляюсь: "А почему не словарь?". С другой стороны, для "малоразовых", думаю - лучше RegExp. Вобщем, Вы опять мою несчастную жизнь с ног на голову... Это же сколько кода мне переосмыслить!!! В смысле, того, что я "наархитектурил" у себя раньше.

Добавлено через 8 минут
А вместо словаря можно каждое слово-критерий сравнить с каждым словом из очередной ячейки. т.е. split в массив, и цикл в цикле перебираем.
Просто забыл. Там ведь так и было. При совпадении, в словарь заганялся адрес ячейки (это была ошибка - нужно было заганять сразу в Union(range), что потом и сделал). Долго это.
0
6922 / 2832 / 543
Регистрация: 19.10.2012
Сообщений: 8,645
08.04.2013, 09:10 56
Попробовал на массиве и с union - как ни странно, 8 секунд.
Вероятно, на каждый union происходит обращение к ячейке, что в итоге только тормозит процесс... Как-то не понятно, не логично...
А этот последний код, если ещё добавить If Len(cc.Value) Then - то 0,6 сек.
Лучший вариант - анализ массива, покраска сразу на листе - менее полсекунды:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Sub tttt()
    Dim cc, odict As Object, el, flag As Boolean
    Dim dblResTime As Double
    Dim stTime As Date
    Dim mstr$, x&
    Dim i&, ii&, a()
 
    Set odict = CreateObject("scripting.dictionary")
    odict.comparemode = 1
 
    mstr = InputBox("Занесіть критерії для пошуку в комірках " & _
                    "ч/з прогалини (можна з комами - тоді можна i без прогалин)." & _
                    Chr(13) & Chr(13) & "Rem. Регістр теж не має значення." & _
                    Chr(13) & Chr(13) & "наприклад :" & _
                    Chr(13) & Chr(13) & "П     г     234     МзН" & _
                    Chr(13) & Chr(13) & _
                    "(К-сть прогалин також значення не мають!)", , "П  г  234  МзН")
    stTime = Timer
 
    Application.ScreenUpdating = False
    With ActiveSheet.UsedRange
        .Interior.ColorIndex = xlNone
        a = .Value
        For i = 1 To UBound(a)
            For ii = 1 To UBound(a, 2)
                cc = a(i, ii)
                x = x + 1
                If Len(cc) Then
                    flag = True
                    odict.RemoveAll
                    For Each el In Split(Replace(cc, ",", " "))
                        odict.Item(el) = 0&
                    Next
                    For Each el In Split(mstr)
                        If Not odict.exists(el) Then flag = False
                    Next
                    If flag Then .Cells(x).Interior.Color = vbRed
                End If
            Next
        Next
    End With
 
    Application.ScreenUpdating = True
 
    dblResTime = Format(Timer - stTime, "#0.00")
    MsgBox "Час   виконання   -   " & dblResTime
 
End Sub
1
4377 / 661 / 36
Регистрация: 17.01.2010
Сообщений: 2,134
08.04.2013, 10:54 57
Не совсем. Какой смысл в покрасте? В тех, старых кодах, я менял форматирование текста не просто так - как намек ТС, что можно с AllCells сразу делать все что хочешь. Ну а все страховки, сообщения например, что ничего не найдено, сколько найдено и т.п., думаю, ему самому это под силу. Если нужно. В любом случае - 8 секунд - это даааалекооо не 36. Наверное, специальность сказывается. Психологически, для меня запускать словарь для проверки содержимого ячейки - это было как запустить большой, мощный бульдозер Kamatsu вместо маленького и шустрого VJC для вертикальной планировки в здоровом и густом саду. Мое личное Вам спасибо за подсказку, помогли барьер сломать.

Добавлено через 13 минут
А! Еще у меня вопрос, если можно. Почему, все-таки, 0&, а не, например, 0%? Нуль - он и есть нуль, но как-будто Integer чуть ли не в два раза меньше места занимает, не помню точно. И в данном случае, он не будет играть роль в "соответствии типов данных". И верхняя граница значения не имеет. Почему не Byte - понятно, а вот почему не Integer - не понятно. Или это какие-то внутренние болезни железячки?
0
6922 / 2832 / 543
Регистрация: 19.10.2012
Сообщений: 8,645
08.04.2013, 11:23 58
На MSDN писалось, что внутри VBA все Integer всё равно переводит в Long, так что Integer смысла не имеет, только тормозит процесс:

http://msdn.microsoft.com/en-u... e.10).aspx

Traditionally, VBA programmers have used integers to hold small numbers, because they required less memory. In recent versions, however, VBA converts all integer values to type Long, even if they are declared as type Integer. Therefore, there is no longer a performance advantage to using Integer variables; in fact, Long variables might be slightly faster because VBA does not have to convert them.
1
4377 / 661 / 36
Регистрация: 17.01.2010
Сообщений: 2,134
08.04.2013, 14:24 59
Нет, ну нормально. А я каждый раз за каждый байт войну веду сам с собой в этих типах!!! Спасибо! Поставлю как заставку при включении Windows.

Добавлено через 2 часа 54 минуты
To Hugo121. Зацепило. Сильно, потому-что с собирательным диапазоном (здесь - AllCells) мне много работать приходится. Поэтому покрутил на перекурах.
Что я сделал? Скомбинировал мое, что раньше, с Вашими последними подсказками. Для общего диапазона - SpecialCells, для собирательного - отдельную коллекцию адресов. Для преобразования строки накидал простенькую функцию func_ProcessPhrase(fStr As String) (жаль было времени искать в сети). Собрал "гибрид".
Время, полное, в т.ч. на форматирование - 1.07 секунды! Все! Диапазоны типа AllCells на полку!!! И подальше!!!

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
Sub SearchAllCells_WithMyCriteries_CorrectedByHugo121()
    Dim mARR(), mRng As Range, currCell As Range, el
    Dim i&, mstr$, counter&, bFlag As Boolean
    Dim dict As Object, coll As Collection
    Dim stTime As Date, dblResTime As Double
    Application.ScreenUpdating = False
        With ActiveSheet
            .Cells.Font.Name = "Tahoma"
            .Cells.Font.Bold = False
            .Cells.Interior.ColorIndex = xlNone
            Set mRng = .UsedRange.SpecialCells(xlCellTypeConstants, 2)
        End With
    Application.ScreenUpdating = True
    ReDim mARR(1 To Application.WorksheetFunction.CountA(mRng), 1 To 2)
        For Each currCell In mRng
            counter = counter + 1
            mARR(counter, 1) = currCell.Address
            mARR(counter, 2) = currCell.Value
        Next
    mstr = func_ProcessPhrase(InputBox("Занесіть критерії для пошуку в комірках " & _
                "ч/з прогалини (можна з комами - тоді можна i без прогалин)." & _
                Chr(13) & Chr(13) & "Rem. Регістр теж не має значення." & _
                Chr(13) & Chr(13) & "наприклад :" & _
                Chr(13) & Chr(13) & "П     г     234     МзН" & _
                Chr(13) & Chr(13) & _
                "(К-сть прогалин також значення не мають!)", , "П  г  234  МзН"))
    stTime = Timer
    Set dict = CreateObject("scripting.dictionary")
    dict.comparemode = 1
    Set coll = New Collection
        For i = LBound(mARR, 1) To UBound(mARR, 1)
            bFlag = True
            dict.RemoveAll
                For Each el In Split(func_ProcessPhrase(CStr(mARR(i, 2))), _
                                                                        "," & Space(1))
                    dict.Item(el) = 0&
                Next
                For Each el In Split(mstr, "," & Space(1))
                    If Not dict.exists(el) Then bFlag = False
                Next
            If bFlag Then coll.Add Item:=mARR(i, 1)
    Next
    Application.ScreenUpdating = False
        For Each el In coll
            With Range(el)
                .Interior.ColorIndex = 35
                .Font.Bold = True
                .Font.Name = "Comic Sans MS"
            End With
        Next
    With ActiveSheet
        .Columns.AutoFit
    End With
    Application.ScreenUpdating = True
    dblResTime = Format(Timer - stTime, "#0.00")
    MsgBox "Час   виконання   -   " & dblResTime
End Sub
 
Private Function func_ProcessPhrase(fStr As String)
' Перетворює фрази на зразок " as,bcd, 125,   x18m" або _
    ' "as   bcd 125  x18m     " -  до вигляду "as, bcd, 125, x18m"
    fStr = LCase(Replace(Application. _
                Trim(Replace(Application.Trim(fStr), ",", " ", 1)), " ", ", ", 1))
    func_ProcessPhrase = fStr
End Function
Кинул все, может кому пригодится просто как принцып для подобного. И что б время не тратить на подобные ошибки.
Hugo! Еще раз спасибо! Я Ваш должник! Можна идти действительно на перекур!
0
6922 / 2832 / 543
Регистрация: 19.10.2012
Сообщений: 8,645
08.04.2013, 14:47 60
Я только не понимаю, зачем собирать в коллекцию адреса, почему сразу не отмечать? Лишний код и цикл... хотя времени особо не займёт.
А идея собрать в один массив адреса и значения интересная, хотя думаю тоже лишнее в данном случае - можно ведь взять в массив только значения (одним движением), а на лист идти по номеру (только specialcells тогда кажется не прикрутить...)
Т.к. тут всё равно получается цикл по ячейкам, чтоб взять в массив - так сразу эти ячейки и анализируйте, и сразу помечайте.
Думаю получится чуть быстрее, если как у Вас смотреть только specialcells.
В общем, вариантов решения уже не счесть
И по большому счёту разница даже в пару секунд роли не играет, вот если объёмы больше и уже десятки секунд разница - тогда есть смысл оптимизировать до мелочей.
Или если работа выполняется в процессе и часто.
0
08.04.2013, 14:47
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
08.04.2013, 14:47
Помогаю со студенческими работами здесь

Поиск в DbGrid по нескольким параметрам
Ребят есть такой поиск DM.ADOTable7.Filter:=' LIKE '+#39+ComboBox1.Text+'%'+#39; if...

Сделать поиск по нескольким параметрам
всем привет. Такого рода вопрос. Как реализовать поиск по параметрам? На данный момент у меня есть...

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

Одновременный поиск по нескольким параметрам
Добрый день! Я студент. В рамках подготовки курсовой необходимо реализовать форму поиска по...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru