Страницы: 1 2 След.
RSS
Отбор уникальных значений, словари и массивы??
 
Друзья, Доброе утро!
Пример во вложении, задача в следующем:
Нужно на второй и третий листы (далее по счету) перенести строки исходя из уникальных значений по cтолбцу F
Я пытался, честно  :(  
Перечитал кучу топиков HUGO, но не смог переложить их на свой пример
 
Т.е. предлагаете написать Вам новый макрос?
Смотрю пример - сразу напрашивается фильтр.
Но проще как начинающему делать так:
циклом по исходному диапазону (или массиву) собираем словарь уникальных значений, каждому новому в item кладём увеличивающийся счётчик (начинаем с 2).
Но сперва проверка - если уникального ещё нет в словаре - заносим в словарь, на лист этого счётчика в первую свободную строку копируем текущую строку.
Если уже есть - извлекаем счётчик-номер листа из словаря, на лист этого счётчика в первую свободную строку копируем текущую строку.
Вот такая схема.
Можно использовать массив при чтении/анализе диапазона, можно использовать массивы и при копировании, но это расточительно по использованию памяти - нужно на каждое уникальное значение создать массив размером с исходный (чтоб точно хватило места), держать его в словаре вместе с счётчиком заполненных строк.
На примере таких всего 2, но представьте что на листе 10000 строк, и там например 100 уникальных - значит нужно будет 100 массивов по 10000 строк!
Или тогда такой ход - сперва анализ всего массива данных, сразу каждому уникальному собираем коллекцию номеров отбираемых строк (коллекция наращивается в процессе).
Затем уже цикл по словарю - создаём массив по размеру очередной коллекции, циклом по коллекции копируем данные из одного массива (исходного) в созданный, выгружаем массив на очередной лист.
Вот так будет и быстро, и на массивах/словарях/+коллекциях  :)

P.S. Т.е. логика использования словаря простая - запоминаем где что лежит, или сколько чего было (или сразу всё вместе). Посмотрите на свою память :)
В данной задаче вторая схема - просмотрели данные, прикинули сколько листов понадобится и какие строки куда будем копировать (сколько их будет).
Далее это реализуем - для скорости копируем через массив, хотя можно и без него копировать строки прямо с листа на лист. Но тогда не нужна коллекция номеров строк - можно просто по ходу дела запоминать на какой лист кого собираем, и просто их пополнять следующей строкой. Это первая схема.
Изменено: Hugo - 26.09.2013 11:04:40
 
Цитата
Я пытался, честно
Чей-то не видно попыток...
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Попытки были без использования словарей и коллекций:

Код
N = 2
For Runner = 2 to 1000
 For Runner2 = 2 to N
 if application.worksheetfunction.countif(range(worksheets(1).cells(2,1), worksheets(1).cells(1000,1)), worksheets(1).cells(runner2,3)) = 0 then
 worksheets(1).cells(runner2,3).value = worksheets(1).cells(runner,1).value
 N = N + 1
 end if
 Next Runner2
Next Runner 

For Runner = 2 to N
 For Runner2 = 2 to 1000
 if worksheets(1).cells(runner,3).value = worksheets(1).cells(runner2,1)).value then
 worksheets(1).cells(runner,4).value = worksheets(1).cells(runner,4).value + worksheets(1).cells(runner2,2)).value
 end if
 Next Runner2
Next Runner


Читаю сейчас кучу ссылок и описаний от ZVI, но теперь уже пробую при помощи словаря. И убил, все что пытался сделать выше
В данный момент не пойму почему если словарю присвоить range, то не работает свойство count
Например:
Код
oDict = Range(Cells(2, 1), Cells(lastrow, 13)).Value
MsgBox oDict.Count

Выходит ошибка Object Required

To HUGO: Очень уважаю ваш труд и поддержку на этом форуме, не хотел чтобы вам показалось что я лентяй. Всего лишь нужен пример, без которого, к сожалению, я не могу понять логику в данной задаче. Точнее логика ясна (обычный автофильтр), нехватает знаний наверное..
Изменено: chernyde - 26.09.2013 12:43:58
 
Оформляйте коды ТЕГОМ!
 
Исправил!
 
Код
Option Explicit

Sub tt()
    Dim a(), i&, t$
    Dim k, el

    With CreateObject("Scripting.Dictionary"): .comparemode = 1

        'собираем словарь
        a = Range([F1], Range("F" & Rows.Count).End(xlUp)).Value
        For i = 2 To UBound(a)
            t = a(i, 1)
            ' если нет в словаре, добавляем с коллекцией
            If Not .exists(t) Then .Add t, New Collection
            .Item(t).Add i    'в коллекцию критерия добавляем номер строки
        Next

        'смотрим что собралось - вместо "смотрим" можно сразу и копировать
        For Each k In .keys
            For Each el In .Item(k)
                Debug.Print k & " - " & el
            Next
        Next
    End With

End Sub
 
Пока не понимаю как это может решить мой вопрос...
Все тоже самое можно сделать, используя ячейки, у которых и так есть номер
Код
lastrow = Range(Range("A1"), Range("A1").End(xlDown)).Rows.Count
for i = 2 to lastrow
msgbox cells(i,5).value & i
next i

Я понимаю, что это быстрее, но пока моя задача хоть как то это сделать, используя даже ячейки, чтобы понять суть, а затем только менять синтаксис и делать все на массивах, коллекциях и словарях.
Один каждый лист должен иметь строки уникальной улицы. При этом каждый раз эта улица будет разной

Вот в этом месте...
Код
For Each k In .keys
            For Each el In .Item(k)
                Debug.Print k & " - " & el
            Next
        Next

...просто перечисляются ячейки со значениями (из словаря или коллекции я не пойму разницы между ними) и выводятся на экран (или копируются, суммируются и т.д.).
Как сделать, чтобы на отдельные листы копировались только те строки, которые:
- были с одной улицой;
- ранее не повторялись;
Изменено: chernyde - 26.09.2013 14:31:18
 
Код
For Each k In .keys 'для каждого уникального ключа
    For Each el In .Item(k) 'получаем строки, которые нужно копировать
        'тут копируем строку el на лист - например на следующий по счётчику, или с именем k, или добавляем поиск соответствия листа и k...
    Next
Next 

Поясняю - имеем словарь с перечнем уникальных значений (улицы), к каждому значению список строк листа/массива, где есть данные по этой улице.
Осталось их взять.

А вот "- ранее не повторялись" это что-то новенькое.
В коллекции они конечно не повторяются (по номеру), а вот про содержимое никто не спрашивал. Что нужно то?
Изменено: Hugo - 26.09.2013 14:45:30
 
Ну вот, смотрите:
На листах "итог1, итог2, итог3" - это то, что в итоге нужно.
То есть, один лист - одна улица. Затем их нужно будет также фильтровать по столбцу К, но это я думаю то же самое решение, поэтому пока опустим.
Сложность в том, что:
- пользоваться придется 6 дней в неделю по нескольку раз
- каждый раз "словарь" улиц будет разным (т.е. может быть 10 улиц, а может быть 50, при этом они могут не повторяться).

Я зацепился за массивы и словари, т.к. думал что они умеют искать уникальные значения и разносить их по листам. Грубо говоря - тупая работа с автофильтрами. И основная проблема, из-за которой я не могу составить логику макроса: как дать понять коду, что нужно брать по-порядку каждую улицу, копировать их содержимое и не повторяться при этом.
 
И опять xlsx? Даже смотреть не буду.
Ну вроде всё уже объяснил, разжевал, осталось только за Вас весь остальной код написать  :)  Не хочу...

P.S. А словари-массивы сами ничего делать не умеют. Это ведь всего лишь 0101...
Изменено: Hugo - 26.09.2013 16:29:05
 
В любом случае спасибо, советов много получил :)

ps. Что дурного в .xlsx?
 
В xlsx нет Ваших попыток написать макрос :)
 
аа, вот о чем вы  :D  
Пробую варианты на реальном примере с реальной мастердатой, а это просто пример для форума вымышленный, скопировал данные, формат оставил изначальный  ;)

Всего доброго!
Изменено: chernyde - 26.09.2013 17:07:21
 
Ну понятно.
Если делать без словаря - значит нужно на каждую строку по названию улицы искать лист, куда будем копировать, затем искать мемто, затем копировать.
С словарём-коллекцией - после первого цикла знаем количество улиц, какие улицы, сколько для каждой строк, какие именно.
Можно даже далее делать так - перебором очередной коллекции собираем Union нужных строк и сразу всю кучу копируем на нужный лист.
 
Цитата
Если делать без словаря - значит нужно на каждую строку по названию улицы искать лист, куда будем копировать,
дадада, вот как раз пробую
 
Можно использовать ВПР() по списку соответствия. Или словарь - загнать в начале в него пары улица-лист, затем извлекать на каждую улицу название её листа :)
Но тогда листы должны быть заготовлены заранее - т.е. сперва нужно вытянуть все уникальные названия улиц, по ним создать листы. С помощью словаря :)
 
ADO
Спасибо
 
Дмитрий, на кнопку макрос забыл посадить  :(
Может на практике ещё нужно будет подстраховаться с именами листов - неразрешённые символы/названия, ограничения по длине... Ну это ко всем вариантам относится, если их генерить автоматически из того, что понаписано в ячейках.
Изменено: Hugo - 27.09.2013 00:42:07
 
Привет Игорь, пусть автор что то и сам сделает. :D
По хорошему надо воткнуть функцию проверки имени формируемого листа.
Спасибо
 
Дима, привет  :)
ОФФ
Цитата
Шарик: Фу! До чего же дичь пошла бестолковая — я полдня за ней бегал, чтобы сфотографировать!
Матроскин: Это еще мало, теперь ты еще за ним полдня бегать будешь.
Шарик: Это почему же?
Матроскин: А чтоб фотографию отдать.
Изменено: KuklP - 27.09.2013 01:25:29
Я сам - дурнее всякого примера! ...
 
Цитата
...ты еще за ним полдня бегать будешь.
Вчера с работы рано пришлось уезжать, а вечером был без доступа к ноуту, но анекдот зачет! :D  

Вариант R Dmitriy очень крутой))
придется с sql теперь разбираться)
Где лучше почитать про adodb объект?
 
А чем мои хуже? Они все проще.
Ааа, их ведь нет "под ключ"... :)
 
Под ключ было бы, если это все работало на моем реальном примере, но для этого мне щас нужно разобраться с параметрами и методами adodb объектов  :D  
Hugo, ваше описание шикарное, все это можно сделать впринципе просто на ячейках, но тяжело без примера, а этот вариант работает, поэтому разберусь для начала с этим, возможно потом как-то упрощу

Ваш форум офигенский, я сюда еще лет 5 назад заходил, когда только знакомился с экселем и все формулы отбора у меня работали на суммпроизв(), я даже про макрорекордер ниразу не слышал, а щас время появилось свободное..
 
для того что ьы работало на реадьном примере необходимо плдключить библиотеку ado в референсах, и помнить про названия листа на котором расположены данные.
Спасибо
 
Вообщем через 1 час у меня заболела голова от объектов БД...
Сделал как всегда - "дешево и сердито". Зато работает. Итак уже очень много времени потратил на это.
Код
Dim a As String
Set main = ActiveWorkbook

exported = Application.GetOpenFilename(Title:="Âûáåðèòå ôàéë âûêà÷êó èç Q4T")
Workbooks.Open Filename:=exported
Set from = ActiveWorkbook

lastrow = Range(Range("A1"), Range("A1").End(xlDown)).Rows.Count
plant = Cells(lastrow, 13).Value
For i = 2 To lastrow
        If Cells(i, 13).Value = plant Then
        Cells(i, 13).Interior.Color = 5296274
        End If
Next i

Workbooks.Add
ActiveWorkbook.SaveAs Filename:=main.Sheets(1).Cells(2, 9).Value & plant & ".xls", FileFormat:=xlNormal, Password:="", WriteResPassword:="", ReadOnlyRecommended:=False, CreateBackup:=False

Set plantsh = ActiveWorkbook

lastrowpl = 1
from.Activate
For i = 2 To lastrow
        from.Activate
        If Cells(i, 13).Interior.Color = 5296274 Then
        Range(Cells(i, 1), Cells(i, 1)).EntireRow.Copy
        plantsh.Activate
        Cells(lastrowpl, 1).PasteSpecial xlPasteValues
        lastrowpl = lastrowpl + 1
        from.Activate
        End If
Next i

For i = lastrow To 2 Step -1
If Cells(i, 13).Interior.Color = 5296274 Then
Range(Cells(i, 1), Cells(i, 1)).EntireRow.Delete xlUp
End If
Next i


Пока не доделал, т.к. нужно еще придумать как данные будут в акты расхождений переноситься
По времени я думаю будет уходить около 60 секунд на `500 строк, меня устраивает.
Потом буду ускорять и делать по другому :) Спасибо за ответы!
 
На 500 строк нужны доли секунды, даже если там 500 улиц. Это без учёта времени создания листов.
А что делает код - сходу и не поймёшь... :(
 
Заносим последнюю строку из списка в переменную plant далее сравниваем ее с остальными ячейками: если равны, то красим заливкой. Создаем книгу, добавляем туда залитые ранее строки и удаляем их из изначального списка. Затем цикл заново, только уже без удаленных строк.

Сейчас без screenupdating false на 150 строк около 10 сек, и это только половина задачи, вообщем не буду скрывать, что колхоз. Но я думаю, что больше 30 секунд уходить не должно, т.к. куча всякого мусора в коде, который лень в порядок приводить...
Изменено: chernyde - 27.09.2013 13:44:18
 
Интересный алгоритм :)
Чем-то напомнило 100 разных вариантов обращения к диапазону у Климова :)
 
Куда мне до профессионалов  8)
Щас время появилось, буду читать верхние топики в этом разделе, через год буду монстром)))
Страницы: 1 2 След.
Наверх