Страницы: 1 2 След.
RSS
Макрос для отбора уникальных значений из ОГРОМНОГО массива, Нужны только уникальные значения
 
Добрый день! Есть массив данных числовых (1 млн строк, 8 столбцов), каждый столбец может иметь разное количество строк. Помогите пожалуйста отобрать уникальные значения и вывести их в столбцы, с учетом максимального количества строк одного из столбцов. Пример во вложении.
 
Цитата
bss17 написал:
1 млн строк, 8 столбцов
Решение, более простое и быстрое или более сложное и медленное, зависит от возможностей вашего компа.
В частности, от гигов памяти и разрядности системы.
В любом случае все через словари или коллекции. (Словарь мне нравится больше для таких случаев.)
 
а стало нужно получить там где было или в сторонке, как в примере?
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
в сторонке желательно, чтобы посмотреть сколько элементов было, сколько стало

Михаил С., техника позволяет, 32 Гб оперативной 64 бита, офис 2017. Наведите на мысль, как млжно словари прикрутить, если диапазоны в разных столбцах?
 
навожу на мысль - словарю по-барабану в скольких диапазонах данные, пихайте в словарь по 1 шт.
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Ну и теперь остается их как-то с условием оттуда вытищить, чтобы не повторялись, верно? В этом-то у меня проблема и есть - каким условием можно отловить уникальные значения?
 
Цитата
bss17 написал:
32 Гб оперативной 64 бита
с такой памятью какие заморочки? Берете UsedRange в массив, проходите по элементам массива, составляете словарь. Потом ключи выгружаете на лист.
 
Михаил С., звучит здорово и вроде даже просто )
 
Цитата
bss17 написал:
офис 2017
?
 
Юрий М, пардон, 2016
 
Не приставай. bss17, значит, и Офис сооветствующий )
 
Интересно, а через SQL и SELECT DISTINCT и UNION список уникальных из столбцов собрать и потом уже заниматься выводом?  
По вопросам из тем форума, личку не читаю.
 
Цитата
Михаил С. написал:
Берете UsedRange в массив
- и вот тут вполне может быть out of memory :(
Особенно если данных много, или usedrange юзер создал на весь лист, или офис х32 - это пока никто не уточнял...
Но в общем пофиг, можно в массив брать по столбцу, сразу и определить максимальную длину, а собирать всё в коллекцию, а оттуда перегрузить в созданный под нужный размер массив (если памяти конечно хватит, а если нет - то в массивы), и это в финале выгрузить в новую книгу/лист/куда угодно.
 
Код
Sub WithOutTake()
  Dim dc, ar(), dt, i&, r&, c&, k&
  dt = [a1].CurrentRegion.Value: Set dc = CreateObject("Scripting.Dictionary")
  ReDim ar(1 To UBound(dt) - 1, 1 To 1): k = 8
  For c = 1 To UBound(dt, 2)
    For r = 2 To UBound(dt)
      If IsEmpty(dt(r, c)) Then Exit For
      If Not dc.exists(dt(r, c)) Then
         dc(dt(r, c)) = 1:  i = i + 1:  ar(i, 1) = dt(r, c)
         If i = UBound(ar) Then
           Cells(2, k).Resize(UBound(ar), 1).Value = ar: i = 0: k = k + 1: ReDim ar(1 To UBound(ar), 1 To 1)
         End If
      End If
    Next
  Next
  If i > 0 Then Cells(2, k).Resize(UBound(ar), 1).Value = ar
End Sub
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Hugo,
Цитата
bss17 написал:
32 Гб оперативной 64 бита, офис 2017
смущает правда 2017, но это прямой угол 90, а вода закипает при 100 градусах.
По вопросам из тем форума, личку не читаю.
 
Цитата
bss17 написал:
вроде даже просто
просто, но не быстро.
Зависит от количества уникальных.
Например, на моем компе 500 000 уникальных - 4.5 сек; 1 000 000 - 20 сек. как-то так.
Цитата
БМВ написал:
а вода закипает при 100 градусах.
Смотря где. В пятигорске при 91. :)
Изменено: Михаил С. - 26.09.2018 22:39:27
 
начитался советов и вот результат

bss17,
а "уникальные" - это единственные (неповторимые), т.е. те, что встречаются только 1 раз, а я собрал список всех значений без повторов.
Изменено: Ігор Гончаренко - 26.09.2018 22:38:46
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Цитата
БМВ написал:
смущает правда 2017
Цитата
bss17 написал:
пардон, 2016
Миша, меня другое смущает )
 
Лень искать есть ли Эксель 2016 х32, но у меня работает х32  Эксель2010, хотя система х64
Изменено: Hugo - 26.09.2018 23:41:14
 
Юра, что именно?

bss17, а у вас случайно, не МАК?
 
Цитата
Ігор Гончаренко написал:
а "уникальные" - это единственные (неповторимые), т.е. те, что встречаются только 1 раз
судя по примеру - уникальные - это обычные уникальные ;)
 
Автор выше (#10) сообщил, что он опечатался: 2017 вместо 2016, но медведь из-за своей самокрутки этого не видит )
 
Цитата
Hugo написал:
но у меня работает х32  Эксель2010
Я х.з., ограничивает ли 32-ой Excel количество памяти, но 32-я система ограничивает то ли 3 то ли 4 гига.
 
Hugo,  да, там и правда не совсем очевидно, запятая делает неоднозначной фразу.

Цитата
Михаил С. написал:
В пятигорске при 91.
хм, вроде и не так высоко. Получается что на мертвом море должна при 107 кипеть.
По вопросам из тем форума, личку не читаю.
 
Доброе время суто
Цитата
БМВ написал:
Интересно, а через SQL и SELECT DISTINCT и UNION список уникальных из столбцов собрать и потом уже заниматься выводом?
Нетбук с 2Гбайт ОЗУ и Excel 2010 32bit отобрал из 8000000 значений в тех восьми столбцах чуть больше 5000000 за 450 секунд.
Код
Public Sub testSpeed()
    Dim pConn As New ADODB.Connection
    Dim pRSet As New ADODB.Recordset
    Dim sSQL As String, t As Single
    t = Timer
    pRSet.CursorLocation = adUseClient
    pConn.Open "DBQ=C:\Path\8kk.xlsb;Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DriverId=1046;MaxBufferSize=2048;PageTimeout=5;ReadOnly=1;"
    sSQL = "Select f1 From [Лист1$] Union Select f2 From [Лист1$] Union Select f3 From [Лист1$] Union Select f4 From [Лист1$] Union Select f5 From [Лист1$] Union Select f6 From [Лист1$] Union Select f7 From [Лист1$] Union Select f8 From [Лист1$]"
    pRSet.Open sSQL, pConn, adOpenStatic, adLockReadOnly
    pRSet.MoveLast
    MsgBox "time " & CStr(Timer - t) & " uniques " & CStr(pRSet.RecordCount)
    pRSet.Close: pConn.Close
End Sub

Если уникальных больше миллиона, то лучше делать на коллекциях - быстрее будет.
P. S. Странно, Виталий был на форуме, но что-то не стал на С++ делать - наверняка через сортировку отбор уникальных был бы секунд за 10.
Изменено: Андрей VG - 26.09.2018 23:07:35
 
Цитата
БМВ написал:
вроде и не так высоко
самолично мерял, четырьмя градусниками различных систем. По работе надо было.
 
Андрей VG, Андрей, интересно сравнить на том же мега быстром нетбуке и данных вариант Ігор Гончаренко,

Off
Цитата
Юрий М написал:
медведь из-за своей самокрутки этого не видит
ну пропустил два поста :-)  что ж теперь и на травe забить? :-)

Цитата
Михаил С. написал:
Я х.з., ограничивает ли 32-ой Excel количество памяти
32 разрядное приложение не возьмет более 2ГБ, сколько б не было у системы, Система x32 использует не более 3,5ГБ, сколько б не было установлено. При этом видит что физически больше, но адресация только в пределах 3,5 .
Цитата
Михаил С. написал:
самолично мерял,
Это ж какое давление должно было быть? https://www.dpva.ru/Guide/GuidePhysics/GuidePhysicsHeatAndTemperature/GuidePh­ysicsHeatAndTemperature...
Или все ж кипела не вода? :-)  
Изменено: БМВ - 27.09.2018 07:50:24
По вопросам из тем форума, личку не читаю.
 
Всем привет!
Цитата
Андрей VG написал:
Странно, Виталий был на форуме, но что-то не стал на С++ делать
Андрей, два момента: с соседнего IT попросили задачу одну интересную решить и вопрос вроде простой, думал пока буду писать через коллекции или словари быстрее накидаю на форуме. Но теперь стало интересно, действительно за сколько же... Напишу сегодня, сравним с прогнозом) я так понял уникальные на весь массив? (еду в дороге, посмотреть исходники не могу) готовый результат выкладываем в столбец, если не помещается в следующий, верно? Андрей, на каких данных тестировал, есть тестовый генератор?
«Бритва Оккама» или «Принцип Калашникова»?
 
bss17, а реальные данные - это в самом деле целые числа в определенном интервале? Или нецелые, но с ограниченным числом знаков после запятой?
Я к чему - можно объявить массив типа Integer или Byte, в примере 0 To 90000, и для каждого исходного числа класть 1 в соотв. эл-т массива. А потом выбрать те эл-ты, которые равны 1. Это должно быть быстро.
Изменено: Казанский - 27.09.2018 11:19:38
 
Цитата
БМВ написал:
Андрей, интересно сравнить на том же мега быстром нетбуке и данных вариант  Ігор Гончаренко
Привет, Михаил.
Лобовая вчерашняя версия на SQL отработала за 237 секунд.
На словаре не дождался, убил Excel после 15 минут работы. На коллекции отработал за 85 секунд.
Код
Public Sub testDictSpeed()
On Error Resume Next
    Dim vData As Variant, iRow As Long, iCol As Long
    Dim lastRowId As Long, lastColId As Long
    Dim pDict As New Collection, vItem As Long
    Dim t As Single, pSheet As Worksheet
    
    t = Timer
    Set pSheet = ActiveSheet
    lastRowId = 1000000: lastColId = 8
    vData = pSheet.Range("A2:H1000001").Value
    For iCol = 1 To lastColId
        For iRow = 1 To lastRowId
            vItem = vData(iRow, iCol)
            pDict.Add vItem, CStr(vItem)
        Next
    Next
    MsgBox "time " & CStr(Timer - t) & " uniques " & CStr(pDict.Count)
End Sub

Быстрее всего получилась версия на SQL с переброской данных в текстовый файл и определением schema.ini – отработало за 35 секунд.
Цитата

[db.txt]
ColNameHeader=True
Format=Delimited( )
MaxScanRows=0
Col1=f1 Long
Код
Public Sub testSql2Speed()
    Dim pSheet As Worksheet, sOut As String
    Dim pConn As New ADODB.Connection, i As Long
    Dim fso As New Scripting.FileSystemObject
    Dim pStream As Scripting.TextStream, t As Single
    Dim pData As New MSForms.DataObject, pRSet As New ADODB.Recordset
    t = Timer
    Set pStream = fso.CreateTextFile("C:\Path\db.txt", True)
    Set pSheet = ActiveSheet
    pStream.WriteLine "f1"
    For i = 1 To 8
        pSheet.Range(pSheet.Cells(2, i), pSheet.Cells(1000001, i)).Copy
        pData.GetFromClipboard
        pStream.Write pData.GetText(1)
    Next
    pStream.Close: Set pStream = Nothing
    pConn.Open "Driver=Microsoft Access Text Driver (*.txt, *.csv);Dbq=C:\Path\;Extensions=asc,csv,tab,txt;"
    pRSet.Open "Select Distinct f1 From [db.txt]", pConn, adOpenStatic, adLockReadOnly
    pRSet.MoveLast
    MsgBox "time " & CStr(Timer - t) & " uniques " & CStr(pRSet.RecordCount)
    pRSet.Close: pConn.Close
End Sub

Цитата
bedvit написал:
готовый результат выкладываем в столбец, если не помещается в следующий, верно? Андрей, на каких данных тестировал, есть тестовый генератор?
Привет, Виталий.
Тестовый пример простой. На Лист1 в первой строке пишем f1..f8
В диапазон A2:H1000001 формула =СЛУЧМЕЖДУ(0;8000000), потом копирование и вставка значений. Выводом на лист массива уникальных с разбивкой по столбцам – не интересовался, по идее это достаточно быстро и тривиально.
Страницы: 1 2 След.
Наверх