Надо придумать шаблон для отбора значений из массива

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
kibernetics
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 945
Зарегистрирован: 03.05.2006 (Ср) 13:31
Откуда: Minsk

Надо придумать шаблон для отбора значений из массива

Сообщение kibernetics » 23.07.2018 (Пн) 23:55

Здарова честной народ!
Всё трудитесь, копошитесь )
Молодца! Я тоже. И я к вам с вопросом:
есть динамический двумерный массив, текстовые ячейки. Колонки и строки.
Так вот у массива есть ключ, который раскинут по контрольным колонкам. Он не постоянный, например: колонки 1,2,5 или 2,9.
Строк много, и надо получить эти ключи. Мне чего-то кажется, что можно как-то сделать паттерн, который бы сразу отбирал ключевые колонки, а не перебором.
Сейчас так сделано:
Код: Выделить всё
Dim arrData(5,10) 'данные
Dim arrTemp() As String 'временный для сплита
Dim sColumns as String
Dim sKey As String

sColumns = "1,2,5"

arrTemp = Split(sColumns, ",")
For i = 0 to Ubound(arrTemp)
     sKey = sKey & arrData(0,arrTemp(i))
Next


вопрос, можно ли тут от цикла избавится?
Конечно было бы круто сделать так:
Код: Выделить всё
sKey = arrData(1) & arrData(2) & arData(5)

но вся соль в том, что sColumns может быть разной длины и набора.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Надо придумать шаблон для отбора значений из массива

Сообщение Хакер » 24.07.2018 (Вт) 10:11

Ну и описание... зачем применять мутный термин «ключ», если это просто подмножество ячеек в каждой строке.

Спасти и убыстрить этот код может только две вещи:
  1. Не использовать неэффективные и невыгодные типы. arrTemp() имеет тип String, хотя должен иметь тип Long — это же абсурд. В итоге тонна работы по валидации и конвертации строк в числа.
  2. Избавится от итеративной конкатенации, поскольку конкатенация это не только посимвольное копирование, но и главным образом выделение памяти под склеенную строку, а выделение — это самое медленное, что здесь может быть, потому что выделение это пробег по структурам, которые держат карту свободного места в кучах/строковом пуле. Вместо этого надо подсчитать длину итоговой строки, выделить одним разом столько памяти, сколько нужно, а потом итеративно скопировать туда фрагменты. Если результат предполагается записывать в файл, отсылать по сети, разом отправлять на принтер — то лучше одним проходом подсчитать место, которое нужно под склейку всех ячеек всех строк, 1 раз выделить большой буфер, вторым проходом всё покопировать в этот большой буфер и потом этот буфер писать в файл (или что-то другое).

Концептуально же, если результат склейки сиюминутно целиком не нужен, а, к примеру, при отображение в каком-нибудь UI-контроле (типа списка) сиюминутно нужны только те строки, которые видимы на экране, лучше использовать on-demand подход, то есть не обрабатывать все строки, а обрабатывать (выделять память под склейки и склеивать) только те, которые нужны именно сейчас.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

kibernetics
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 945
Зарегистрирован: 03.05.2006 (Ср) 13:31
Откуда: Minsk

Re: Надо придумать шаблон для отбора значений из массива

Сообщение kibernetics » 24.07.2018 (Вт) 10:43

Благодарю любезнейший! Рад, тебя слышать.
По ходу мне применим лишь первый пункт. Здесь да, буду передавать на вход не строку, а сразу готовый массив с лонгами. Сплит я сделал чтобы упростить создание массива из списка. Жаль, что сплит не работает для массивов отличных от строковых. И чтобы сделать массив лонгов потребуется итерация.
А с выделением определённого размера буфера, то это не представляется возможным, в виду того, что не известно изначально какой длины данные будут в склеенной строке.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Надо придумать шаблон для отбора значений из массива

Сообщение Хакер » 24.07.2018 (Вт) 11:23

kibernetics писал(а):А с выделением определённого размера буфера, то это не представляется возможным, в виду того, что не известно изначально какой длины данные будут в склеенной строке.

Один пробег замеряет этот размер, суммируя длины маленьких строк.
Потом выделение одного большого буфера.
Второй пробег копирует маленькие кусочки, один за другим.

Это куда быстрее, чем то, что ты хочешь делать, несмотря на то, что прогона два.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

kibernetics
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 945
Зарегистрирован: 03.05.2006 (Ср) 13:31
Откуда: Minsk

Re: Надо придумать шаблон для отбора значений из массива

Сообщение kibernetics » 24.07.2018 (Вт) 12:27

Т.е. двойной проход быстрее?
Код: Выделить всё
Dim arrData(5,10) 'данные
Dim arrTemp(2) As Long
'Dim sColumns as String
Dim sKey As String
Dim iSum As Integer
Dim beginLine As Integer

'sColumns = "1,2,5"
'arrTemp = Split(sColumns, ",")
arrTemp(0) = 1
arrTemp(1) = 2
arrTemp(2) = 5

For i = 0 to Ubound(arrTemp)
     iSum = iSum & Len(arrData(0,arrTemp(i)))
Next

sKey = Space(iSum)
beginLine = 1
For i = 0 to Ubound(arrTemp)
     iSum = Len(arrData(0,arrTemp(i)))
     Mid(sKey, beginLine, iSum) = arrData(0,arrTemp(i))
     beginLine = beginLine + iSum
Next

будет быстрее, чем просто конкатенация?
Код: Выделить всё
For i = 0 to Ubound(arrTemp)
     sKey = sKey & arrData(0,arrTemp(i))
Next

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

Re: Надо придумать шаблон для отбора значений из массива

Сообщение alibek » 24.07.2018 (Вт) 12:35

Разумеется.
Но необязательно делать двойной проход.
Можно просто делать изначально большой буфер, а если его вдруг не хватит, то удваивать.
Lasciate ogni speranza, voi ch'entrate.

kibernetics
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 945
Зарегистрирован: 03.05.2006 (Ср) 13:31
Откуда: Minsk

Re: Надо придумать шаблон для отбора значений из массива

Сообщение kibernetics » 24.07.2018 (Вт) 12:49

Вот так. Век живи - век учись.
Спасибо

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Надо придумать шаблон для отбора значений из массива

Сообщение Хакер » 24.07.2018 (Вт) 13:10

Код: Выделить всё
Mid(sKey, beginLine, iSum) = arrData(0,arrTemp(i))

Mid медленный и плохой. Чуть лучше будет Mid$. И намного лучше (но травмоопасно) будет — RtlMoveMemory. Разница в очках медлительности не как 3—2—1, а как 30—20—1. Но неправильное объявление RtlMoveMemory может превратить картину в 30—20—25. Правильное объявление — это никаких As String в аргументах RtlMoveMemory, а только As Any/As Long.

Множественных обращений к элементам массива стоит избегать. Это касается повторяющихся arrTemp(i) и arrData(0,arr1Temp(i)). Причем если первое решается использованием переменной, то второе не решается. Но решается использованием процедуры в ByRef-аргументом.

Маленькие буферы под каждую строку матрицы в общем случае хуже, чем один большой однократно выделяемый буфер под все строки. И вообще, по какой-то неведомой причине код написан так, как будто идёт обработка только первой строки массива. Число операций по выделению и перевыделению памяти должно быть предельно минимизировано.

Названия переменных — это отдельный треш. Что за beginLine? Это звучит как призыв действию, как «начни строку». cchCopyOffset — вот нормальное название. И вместо iSum — cchFragmentLength. Ну и так далее.

alibek писал(а):Можно просто делать изначально большой буфер, а если его вдруг не хватит, то удваивать.

Так допустимо делать, но в данном случае это вредно. Bottleneck в производительности — именно операции выделения памяти под строки. С таким подходом при неоптимальном подборе констант «начальный размер буфера» и «шаг/коэффициент увеличения» на одну строку матрицы может прийтись множество операций выделение нового строкового буфера + освобождение старого, что почти уровняет производительность с вариантом «тупо конкатенация в цикле». А даже при оптимальном подборе на каждую строку исходной матрицы придётся как минимум две операции выделения, потому что изначально избыточные буфер придётся урезать, а это означает создание нового строкового буфера меньшей длины, копирование и уничтожение старого.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Надо придумать шаблон для отбора значений из массива

Сообщение Mikle » 24.07.2018 (Вт) 14:13

Хакер писал(а):Mid медленный и плохой. Чуть лучше будет Mid$

До сих пор считал, что это синонимы. Век живи - век учись.

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Надо придумать шаблон для отбора значений из массива

Сообщение The trick » 24.07.2018 (Вт) 16:27

Mikle писал(а):
Хакер писал(а):Mid медленный и плохой. Чуть лучше будет Mid$

До сих пор считал, что это синонимы. Век живи - век учись.

Обрати внимание на типы аргументов.
UA6527P

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Надо придумать шаблон для отбора значений из массива

Сообщение Mikle » 24.07.2018 (Вт) 19:57

The trick писал(а):Обрати внимание на типы аргументов.

Хм... действительно. Непонятно только зачем это нужно, Mid$ работает так же, как и Mid, даже в таких нетипичных ситуациях:
Код: Выделить всё
Option Explicit

Private Sub Form_Load()
  Dim a, b
 
  a = 123456
  b = Mid$(a, 2, 2)
  Caption = b
End Sub

Teranas
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 224
Зарегистрирован: 13.12.2008 (Сб) 4:26
Откуда: Новосибирск

Re: Надо придумать шаблон для отбора значений из массива

Сообщение Teranas » 24.07.2018 (Вт) 20:47

Хакер
Чё-то нифига не по-вашему, смотрите:

Код: Выделить всё
Option Explicit

Private Sub Form_Load()
  Dim t1 As Single, i As Long
  Dim sTmp As String, s8 As String
  sTmp = String(15000, "R")
  t1 = Timer
  For i = 0 To 1000000
    s8 = Mid(sTmp, 12546, 8)
  Next i
  Text1.Text = CStr(Timer - t1)
  ' 0,1871875
 
  t1 = Timer
  For i = 0 To 1000000
    s8 = Mid$(sTmp, 12546, 8)
  Next i
  Text2.Text = CStr(Timer - t1)
  ' 0,1530625
 
  t1 = Timer
  For i = 0 To 1000000
    s8 = Mid(sTmp, 12546, 8)
  Next i
  Text1.Text = CStr(Timer - t1)
  ' 0,1861875
 
  t1 = Timer
  For i = 0 To 1000000
    s8 = Mid$(sTmp, 12546, 8)
  Next i
  Text2.Text = CStr(Timer - t1)
  ' 0,1488125
End Sub

С уважением, Андрей.

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Надо придумать шаблон для отбора значений из массива

Сообщение ALX_2002 » 24.07.2018 (Вт) 21:20

kibernetics, приветствую ! А можно увидеть ради чего это делается и какие исходные данные, дабы рассуждать не абстрактно, а более конкретно ?

kibernetics
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 945
Зарегистрирован: 03.05.2006 (Ср) 13:31
Откуда: Minsk

Re: Надо придумать шаблон для отбора значений из массива

Сообщение kibernetics » 24.07.2018 (Вт) 23:43

ALX_2002 писал(а):kibernetics, приветствую ! А можно увидеть ради чего это делается и какие исходные данные, дабы рассуждать не абстрактно, а более конкретно ?

Привет.
На базу приходят прайс-листы. В них список товаров. Накидано, кто во что горазд. Ключа/id нет. Надо составлять самому согласно определённых столбцов.
Например,
Мука хлебопекарная; Сорт 1; Производство Россия; 1тонна; 200p.
Мука пшеничная; Сорт высший; Производство Украина; 100кг; 300p.
и т.д.
Я определяю, что ключом здесь выступают столбцы 1 и 2.
И теперь прогоном считываю строку, сравниваю с неким эталоном в глобальной БД, что изменилось/удалилось/добавилось.

Беру следующий список, там порядок столбцов уже иной, к примеру:
1; Мука пекарская; ГОСТ12345; 10тонн; 500p.
2; Мука пшеничная; ГОСТ54321; 200кг; 400p.
тут уже ключевые столбцы 2 и 3. Опять-таки, надо пройти по массиву и отобрать данные.

ну вот такие данные. Столбцов(полей) до 20, строк(записей) в списке, в среднем 10.000.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Надо придумать шаблон для отбора значений из массива

Сообщение Хакер » 24.07.2018 (Вт) 23:55

Teranas писал(а):Чё-то нифига не по-вашему, смотрите:

Хотя экспериментальный код не совсем правильно написано, что «нифига не по моему»-то? Как раз вся подтверждает мои слова. Mid$ оказался быстрее.

Числа 30-20-1 были написаны от балды из головы, без каких-то замеров. Твой код даёт вот такие результаты в режиме отладки:
Код: Выделить всё
Mid  - 0.09447
Mid$ - 0.07775

В скомпилированном виде:
Код: Выделить всё
Mid  - 0.093
Mid$ - 0.06322657

что вполне себе соответствует моей оценке «очков тормознутости».
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Teranas
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 224
Зарегистрирован: 13.12.2008 (Сб) 4:26
Откуда: Новосибирск

Re: Надо придумать шаблон для отбора значений из массива

Сообщение Teranas » 25.07.2018 (Ср) 0:01

Если бы их было миллионов десять, тогда можно было думать об оптимизации, а с десятью тысячами...
С уважением, Андрей.

kibernetics
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 945
Зарегистрирован: 03.05.2006 (Ср) 13:31
Откуда: Minsk

Re: Надо придумать шаблон для отбора значений из массива

Сообщение kibernetics » 25.07.2018 (Ср) 1:25

Teranas писал(а):Если бы их было миллионов десять, тогда можно было думать об оптимизации, а с десятью тысячами...

А мне всё равно было интересно. Узнал что-то новое. Всегда не лишне послушать уважаемых людей.
К тому же, прайсов куча, и когда они парсятся ежедневно стопками, то даже сокращение на 1 минуту на каждом, приносит ощутимые плоды. Может не так ощущается на первый взгляд, но когда каждый день, то каждая минута считается.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Надо придумать шаблон для отбора значений из массива

Сообщение Хакер » 25.07.2018 (Ср) 1:50

Что уж там.

Я сейчас в ходе эксперимента выяснил, что
Код: Выделить всё
Dim buffer As String
Mid(buffer, x, y) = ...

и
Код: Выделить всё
Dim buffer As String
Mid$(buffer, x, y) = ...


компилируется в идентичный код — в обращения к __vbaMidStmtBstr (что соответствует Mid$), а не к разным функциям, как это ожидается (к __vbaMidStmtVar и __vbaMidStmtBstr соответственно).

Но это относится только к случаю, когда Mid/Mid$ стоит слева от оператора присваивания.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Надо придумать шаблон для отбора значений из массива

Сообщение ger_kar » 25.07.2018 (Ср) 17:37

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

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Надо придумать шаблон для отбора значений из массива

Сообщение ALX_2002 » 29.07.2018 (Вс) 13:45

А мне вот интересно, возможно ли присутствие разделителя ";" в данных ? И если да, то как решается вопрос экранировки. И думал ли об этом ТС 8) ?

kibernetics
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 945
Зарегистрирован: 03.05.2006 (Ср) 13:31
Откуда: Minsk

Re: Надо придумать шаблон для отбора значений из массива

Сообщение kibernetics » 30.07.2018 (Пн) 23:38

ALX_2002 писал(а):А мне вот интересно, возможно ли присутствие разделителя ";" в данных ? И если да, то как решается вопрос экранировки. И думал ли об этом ТС 8) ?

Дорогой друг!
Ты такой странный ) Ну конечно же это не роботы пишут, а менеджеры.
Я, правда, не видел точки с запятой в данных, но сам понимаешь, это неорганизованные данные, мало ли что может произойти.

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Надо придумать шаблон для отбора значений из массива

Сообщение ALX_2002 » 31.07.2018 (Вт) 0:17

kibernetics, тогда, ради интереса, погляди. Может будет полезно.

1) Для чтения записей в примере использован адаптер Jet OleDB 4. Это позволяет тебе делать выборку SQL запросом с сортировкой, отбором и т.п. функционалом
2) Настройка файла schema.ini позволяет выбрать какие поля как интерпретировать (имя поля, тип данных, выделенный под них буффер + форматирование дат и т.д.)
Ссылка по настройке schema.ini - клац
3) Обход проблемы с разделителем в данных решён заключением данных в двойные кавычки (это механизм самого адаптера). Пример - "a;a"
4) В дополнение, добавил в сэмпл использование XSLT шаблона для преобразования выгруженного XML рекордсета в HTML. Может это тебе тоже пригодится.
Вложения
ado.zip
(4.03 Кб) Скачиваний: 174

kibernetics
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 945
Зарегистрирован: 03.05.2006 (Ср) 13:31
Откуда: Minsk

Re: Надо придумать шаблон для отбора значений из массива

Сообщение kibernetics » 31.07.2018 (Вт) 0:37

ALX_2002 писал(а): тогда, ради интереса, погляди. Может будет полезно.

то, что ты гуру скриптинга, никто не сомневался. И я лишний раз в этом убеждаюсь. Здесь, у тебя один файл с данными data.txt, а мне надо data.txt но с разным набором полей. Конвертировать все файлы-эксели вначале в единый вид перед обработкой? Что если во втором файле не будет поля id?

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Надо придумать шаблон для отбора значений из массива

Сообщение ALX_2002 » 31.07.2018 (Вт) 11:25

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

1) Я ни разу не "гуру" скриптинга. Это ошибочное утверждение.

kibernetics писал(а): Здесь, у тебя один файл с данными data.txt, а мне надо data.txt но с разным набором полей.


2) Имя файла "data.txt" взято для примера. Ты можешь называть файлы как угодно. Можешь внутри schema.ini сделать секции для разных файлов с разными настройками. Можешь создавать schema.ini налету, можешь использовать schema.ini из разных подкаталогов меняя рабочую папку. Тут всё зависит от тебя и от рациональности для решения конкретной задачи.

Пример:
Код: Выделить всё
[data.txt]
CharacterSet   = ANSI 
ColNameHeader   = False
Format      = Delimited(;)
Col1      = "ID" Long
Col2      = "Description" Text Width 30
Col3      = "Weight" Long Width 40
Col4      = "Price" Currency Width 40

[data1.txt]
CharacterSet   = ANSI 
ColNameHeader   = False
Format      = Delimited(;)
Col1      = "Col1" Long
Col2      = "Col2" Text Width 30
Col3      = "Col3" Long Width 40
Col4      = "Col4" Currency Width 40


kibernetics писал(а):Конвертировать все файлы-эксели вначале в единый вид перед обработкой?


3) (c) Штирлиц ещё никогда не был так близок к провалу.

8) Выражение "файлы-эксели" режет глаз. Насколько я понимаю, у тебя не "файлы-эксели", а csv файлы или текстовые файлы с разделителями. К Excel-ю они имеют такое же отношение как к корове седло. То что Excel имеет возможность работать с такими файлами не говорит о том, что это его родной формат. И конвертировать что либо совершенно не нужно без надобности.

kibernetics писал(а):Что если во втором файле не будет поля id?


Думаю я исчерпывающе пояснил это в пункте №2. :wink:

kibernetics
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 945
Зарегистрирован: 03.05.2006 (Ср) 13:31
Откуда: Minsk

Re: Надо придумать шаблон для отбора значений из массива

Сообщение kibernetics » 02.08.2018 (Чт) 0:21

ALX_2002 писал(а):Думаю я исчерпывающе пояснил это в пункте №2. :wink:

В принципе, интересный вариант сам по себе. Незнаю, насколько он пользуется популярностью у народа. Т.е. у тебя по сути шаблоны уже предопределены в schema.ini. Что, в общем-то вполне претендует на ответ на мой вопрос.
Извините за длительную дискуссию, не ожидал что так может далеко зайти. Не исключено, что воспользуюсь советом ALX_2002, но предварительно надо будет проделать некоторые тесты, чтобы понять насколько это удобно.
Большое спасибо за идею, а всем остальным за беседу и советы!


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

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

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

    TopList