1392 / 849 / 92
Регистрация: 08.02.2017
Сообщений: 3,625
Записей в блоге: 2

Правильная конкатенация

18.04.2023, 02:34. Показов 6049. Ответов 117
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
На другом форуме видел такой вариант конкатенации большого массива и он мне очень понравился, поскольку скорость близкая к join. На сколько я знаю тип String это структура содержащая в себе массив символов и еслиб у нас был доступ к этому массиву и возможность делать что-то вроде redim preserve.. В общем, можно ли как-то улучшить алгоритм, чтоб закасматить окончательно етот join? )
25.02.2012 08:28:33
Если правильно делать конкатенацию в цикле, то Join отдыхает:

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
' Правильная конкатенация в цикле  
Sub FastConcat()  
 Dim x, t!, i&, j&, s$, v$  
 With Range("A1:Z65536")  'For i = 1 To 1703936: arr(i) = 1: Next
   .Value = 1  
   t = Timer  
   s = " "  
   For Each x In .Value  
     v = x & ";"  
     j = i + Len(v)  
     If j > Len(s) Then s = s & Space$(Len(s))  
     Mid$(s, i + 1) = v  
     i = j  
   Next  
   s = Left$(s, j - 1)  
   Debug.Print Timer - t  
 End With  
End Sub  
 
' Вариант с Join  
Sub io()  
 Dim t As Single  
 Dim x, z(), i As Long, line As String  
 With [A1:Z65536]
   .Value = 1  
   t = Timer  
   ReDim z(1 To .Cells.Count)  
   For Each x In .Value  
     i = i + 1  
     z(i) = x  
   Next  
   line = Join(z, ";")  
   Debug.Print Timer - t  
 End With  
End Sub
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
18.04.2023, 02:34
Ответы с готовыми решениями:

Из символов одного текста строковых функций о операций конкатенация получить другой текст
Из символов одного текста с помощью строковых функций о операций конкатенация получить другой текст. Из «информатика» получить «форма»...

Правильная обработка ошибок
Здравствуйте. У меня такой вопрос. Программа сама записывает файл по сети. Если сеть выключенна то на том компьюторре на котором работает,...

конкатенация строки
добрый вечер. не могу сообразить как сделать конкатенацию строки в цикле. допустим нужно вывести в переменную строкового типа следующее...

117
Испарился
 Аватар для HackerVlad
1742 / 638 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
12.09.2023, 17:09
Студворк — интернет-сервис помощи студентам
testuser2, я рад, что у тебя всё получилось)))
0
1392 / 849 / 92
Регистрация: 08.02.2017
Сообщений: 3,625
Записей в блоге: 2
12.09.2023, 17:50  [ТС]
Цитата Сообщение от testuser2 Посмотреть сообщение
Также видна работа команды redim preserve, то, что при увеличении массива можно по прежнему использовать тот же указатель.
Структура то на месте, а вот данные массива, судя по всему перезаписываются, поскольку указатели на элементы массива меняются после redim preserve..
0
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
12.09.2023, 20:02
Лучший ответ Сообщение было отмечено testuser2 как решение

Решение

Работать непосредственно с символами можно без проблем замапив SAFEARRAY дескриптор на данные:
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
Option Explicit
 
Private Const FADF_AUTO  As Long = 1
 
Private Type SAFEARRAYBOUND
    cCount              As Long
    lBound              As Long
End Type
Private Type SAFEARRAY1D
    cDims               As Integer
    fFeatures           As Integer
    cbElements          As Long
    cLocks              As Long
    pvData              As Long
    Bounds              As SAFEARRAYBOUND
End Type
 
Private Declare Sub PutMem4 Lib "msvbvm60" ( _
                    ByRef pAddr As Any, _
                    ByVal pVal As Long)
Private Declare Function ArrPtr Lib "msvbvm60" _
                         Alias "VarPtr" ( _
                         ByRef ppSA() As Any) As Long
                         
Private Sub Form_Load()
    Dim sString As String
    Dim tSADesc As SAFEARRAY1D
    Dim iText() As Integer
    Dim lIndex  As Long
    
    sString = "Hello"
    
    With tSADesc
        .cDims = 1
        .cbElements = 2
        .fFeatures = FADF_AUTO
        .pvData = StrPtr(sString)
        .Bounds.cCount = Len(sString)
    End With
    
    PutMem4 ByVal ArrPtr(iText), VarPtr(tSADesc)
    
    For lIndex = 0 To UBound(iText)
        iText(lIndex) = iText(lIndex) Xor &H20
    Next
    
    Debug.Print sString
    
End Sub
1
1392 / 849 / 92
Регистрация: 08.02.2017
Сообщений: 3,625
Записей в блоге: 2
13.09.2023, 02:34  [ТС]
The trick, Спасибо за более подробный разбор структуры SafeArray, но еще можно добавить, что надо всегда запоминать прежние указатели, и возвращать потом их на место (для vba это критичный момент)

Добавлено через 13 минут
Цитата Сообщение от The trick Посмотреть сообщение
PutMem4 ByVal ArrPtr(iText), VarPtr(tSADesc)
Это момент еще бы надо как-то осмыслить. Если в одном случае (в товоей статье про указатели) для получения указателя испльзовалась отдельная процедура GetSa, то здесь как то просто, ArrPtr..
0
1392 / 849 / 92
Регистрация: 08.02.2017
Сообщений: 3,625
Записей в блоге: 2
13.09.2023, 14:22  [ТС]
Все, понял как это работает, благодаря коду Анатолия. Получается, что VarPtr(ArrPtr) в случае с массивом дает нам адрес, места где находится указатель на структуру (SAFEARRAY1D). Поменяв этот указатель, мы легко можем залинковать переменнюу массива на свою структуру (как в данном случае), или на структуру другого массива, фактичеки сделав указатель-клон другого массива, который не будет сбиваться, даже если сделать redim preserve. На vba так будет рабоать без вылета, нужно только вернуть прежнее состояние массива (обнулить указатель) в конце.
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
Private Sub Form_Load3()
    Dim sString As String
    Dim tSADesc As SAFEARRAY1D
    Dim iText() As Integer
    Dim lIndex  As Long
    
    sString = "Hello Words"
    
    With tSADesc
        .cDims = 1
        .cbElements = 2
        .fFeatures = FADF_AUTO
        .pvData = StrPtr(sString)
        .Bounds.cCount = Len(sString)
    End With
    
'    PutMem4 ByVal ArrPtr(iText), VarPtr(tSADesc)
    CopyMemory ByVal ArrPtr(iText), VarPtr(tSADesc), 4    ' меняем указатель массива iText() на адрес структуры tSADesc
    
    For lIndex = 0 To UBound(iText)
        iText(lIndex) = iText(lIndex) Xor &H20
    Next
    
    Debug.Print sString
    
'    PutMem4 ByVal ArrPtr(iText), 0&
    CopyMemory ByVal ArrPtr(iText), 0&, 4                  ' восстанавливаем прежний указатель массива iText (0 - непроинициализированый)    
End Sub
0
Испарился
 Аватар для HackerVlad
1742 / 638 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
13.09.2023, 16:07
testuser2, нифигасебе ты заморочился)
0
1392 / 849 / 92
Регистрация: 08.02.2017
Сообщений: 3,625
Записей в блоге: 2
13.09.2023, 17:48  [ТС]
HackerVlad, еще бы с устройтвом 2мерного массива разобраться (в Екселе 2 мерные часто используются), и можеть сделать, какой-нибудь join для 2мерного массива..

Добавлено через 1 час 17 минут
x64 vba-совместимый вариант
Кликните здесь для просмотра всего текста
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
Private Declare PtrSafe Function ArrPtr Lib "VBE7" Alias "VarPtr" (Src() As Any) As LongPtr
Private Declare PtrSafe Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
 
Private Type SAFEARRAYBOUND
    cCount              As Long
    lBound              As Long
End Type
Private Type SAFEARRAY1D
    cDims               As Integer
    fFeatures           As Integer
    cbElements          As Long
    cLocks              As Long
    pvData              As LongPtr
    Bounds              As SAFEARRAYBOUND
End Type
Private Const FADF_AUTO  As Long = 1
 
Private Sub Form_Load3()
    Dim sString As String
    Dim tSADesc As SAFEARRAY1D
    Dim iText() As Integer
    Dim lIndex  As Long
    Dim lnull As LongPtr
    
    sString = "Hello Words x64 Compatible"
    
    With tSADesc
        .cDims = 1
        .cbElements = 2
        .fFeatures = FADF_AUTO
        .pvData = StrPtr(sString)
        .Bounds.cCount = Len(sString)
    End With
    
    CopyMemory ByVal ArrPtr(iText), VarPtr(tSADesc), Len(lnull)    ' меняем указатель массива iText() на адрес структуры tSADesc
    
    For lIndex = 0 To UBound(iText)
        iText(lIndex) = iText(lIndex) Xor &H20
    Next
    
    Debug.Print sString
    
    CopyMemory ByVal ArrPtr(iText), lnull, Len(lnull)              ' восстанавливаем прежний указатель массива iText (0 - непроинициализированый)
 
End Sub
0
Испарился
 Аватар для HackerVlad
1742 / 638 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
13.09.2023, 19:33
Цитата Сообщение от testuser2 Посмотреть сообщение
и можеть сделать, какой-нибудь join для 2мерного массива..
а мне это зачем? я не умею делать join и для простого массива даже))) ни разу небыло нужно вообще

Добавлено через 59 секунд
да и вместо двухмерного массива мне проще массив структуры использовать) с нужными атрибутами)))
0
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
13.09.2023, 20:17
Цитата Сообщение от testuser2 Посмотреть сообщение
что надо всегда запоминать прежние указатели, и возвращать потом их на место
По идеи тут не нужно, т.к. установлен флаг FADF_AUTO.

Цитата Сообщение от testuser2 Посмотреть сообщение
Это момент еще бы надо как-то осмыслить. Если в одном случае (в товоей статье про указатели) для получения указателя испльзовалась отдельная процедура GetSa, то здесь как то просто, ArrPtr..
Да ArrPtr возвращает указатель на переменную которая содержит дескриптор массива. Нужно уточнить что для массива String или UDT содержащей String нужно использовать отдельное объявление.
0
1392 / 849 / 92
Регистрация: 08.02.2017
Сообщений: 3,625
Записей в блоге: 2
14.09.2023, 18:06  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
По идеи тут не нужно, т.к. установлен флаг FADF_AUTO.
В vba, как я понял, указатели возвращать нужно везде, кроме, тех, которые меняются в стеке.
С SafeArray разных размерностей и типов, более менее освоился. У всех массивов данные в сущности являются единым блоком, который можно представить как вектор (1d массив). Если это матрица, то элементы располагаются постолбечно.
Прямой доступ к данным вариантного 2мерного массива:
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
Private Type sVariant
    c As Currency
    s As String
    l As Long
End Type
 
Sub fsf() 
    Dim arr1() As sVariant, arr2()
    Dim tSADesc As SAFEARRAY1D
    
    ReDim arr2(2, 0)
    arr2(0, 0) = "ппвпппып"
    arr2(2, 0) = "ffffafaf"
    
    With tSADesc
        .cDims = 1
        .cbElements = 16
        .fFeatures = FADF_AUTO
        .pvData = VarPtr(arr2(0, 0))
        .Bounds.cCount = UBound(arr2) + 1 '- LBound(arr2)
    End With
    CopyMemory ByVal ArrPtr(arr1), VarPtr(tSADesc), 4
    
    Debug.Print arr1(0).s; vbCr; arr1(2).s
    
    CopyMemory ByVal ArrPtr(arr1), 0&, 4      
End Sub
0
1392 / 849 / 92
Регистрация: 08.02.2017
Сообщений: 3,625
Записей в блоге: 2
16.09.2023, 04:50  [ТС]
Цитата Сообщение от HackerVlad Посмотреть сообщение
а мне это зачем? я не умею делать join и для простого массива даже))) ни разу небыло нужно вообще
Дело може быть не в joinе как таковом, а в лучшем понимании, как правильней работать с памятью. Ведь правильней же лучше?
Вот, к слову, интересная страничка, пока не уловил, в чем там суть. Кто поймет объясните в общих чертах если не трудно.
0
Испарился
 Аватар для HackerVlad
1742 / 638 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
16.09.2023, 12:13
Цитата Сообщение от testuser2 Посмотреть сообщение
пока не уловил, в чем там суть
я тоже если честно не понял, зачем было писать GetMem функции на основе CopyMemory тупость какая-то
0
1392 / 849 / 92
Регистрация: 08.02.2017
Сообщений: 3,625
Записей в блоге: 2
16.09.2023, 13:01  [ТС]
У меня по его тестам, api функция, оказалась значительно быстрее, чем его реализация, но кто его знает, может было бы по другому, на x64 c последними обновлениями и включенным "защитником". У него без CopyMemory как-то работает, почему-то используется variant..
0
Испарился
 Аватар для HackerVlad
1742 / 638 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
16.09.2023, 14:27
testuser2, да не обращай внимания на этот код вообще
0
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
16.09.2023, 14:30
testuser2, любая API функция объявленная так будет тормозить на любых данных где есть строки.
0
1392 / 849 / 92
Регистрация: 08.02.2017
Сообщений: 3,625
Записей в блоге: 2
16.09.2023, 15:17  [ТС]
Цитата Сообщение от HackerVlad Посмотреть сообщение
не обращай внимания
Может быть, но все же, хотелось бы сказать пару слов. Во-первых спасибо человеку, за проделаную работу, код довольно не простой, там есть мысль. Если код хороший - отлично, если код не очень хороший, тоже не плохо, значит есть повод сказать, что-нибудь умное (или подумать) ). Немного поразбираем , что там происходит. 1 тест: для копирования 1 байта (в длинном цикле) у него во первых происходит 2 раза вызов VarPtr, возвращающую Long (4 байта, уже хорошо )), далее эти 4 байта передаются, по значению, в MemByte, то беж копируются в стек.
Visual Basic
1
VarPtr, MemByte(VarPtr(x1)) = MemByte(VarPtr(x2))
Visual Basic
1
2
3
Public Property Get MemByte(ByVal memAddress As LongPtr) As Byte   
        RemoteAssign rm, memAddress, rm.remoteVT, vbByte + VT_BYREF, MemByte, rm.memValue    
End Property
Внутри MemByte "выстреливает" процедура с аж 6 аргументами, 3 из которых Varint, 1 структура с двумя "вариантами" но все это передается по ссылке (по 4 байта), один аргумент по значению, но также имеет размер 4 байта. 6*4 = 24 байта - размер стека. Внутри этой функции происходит 2 4байтных присвоения (то беж копирования), и 2 вариантных.. При том этот RemoteAssign каждый раз по 4 раза долбает.. В общем все это кучерявинько как то.. )
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
Private Sub RemoteAssign(ByRef rm As REMOTE_MEMORY _
                       , ByRef memAddress As LongPtr _
                       , ByRef remoteVT As Variant _
                       , ByVal newVT As VbVarType _
                       , ByRef targetVariable As Variant _
                       , ByRef newValue As Variant)
    rm.memValue = memAddress
    If Not rm.isInitialized Then InitRemoteMemory rm
    remoteVT = newVT
    targetVariable = newValue
    remoteVT = vbEmpty 'Stop linking to remote address, for safety
End Sub
0
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
16.09.2023, 15:22
Такое вообще проще сделать через SAFEARRAY. Сделать Long массив размером от 0 до 536870912 и адресовать всю память. Для Byte и Integer просто битовыми масками выделять нужную часть. Для 64 бит так уже не получится придется динамически подгонять размер или указатель т.к. там 64 битная адресация.
1
1392 / 849 / 92
Регистрация: 08.02.2017
Сообщений: 3,625
Записей в блоге: 2
16.09.2023, 15:59  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
Сделать Long массив размером от 0 до 536870912 и адресовать всю память.
Не совсем понял о чем речь. Ну то есть знаю, что можно на блок данных массива сослать что угодно и сам массив можно сослать на что угодно. Какие сложности могут быть с 64бит?, знаю, только, что там размер указателя 8 байт и если нужно сделать массив указателей, то выбрать тип LongPtr или LongLong для массива.
0
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
16.09.2023, 16:05
Цитата Сообщение от testuser2 Посмотреть сообщение
Не совсем понял о чем речь.
Все тоже самое что тут только .pvData = 0, а .Bounds.cCount = 536870912. Получается что можно адресовать всю память от 0 до 0x7fffffff с шагом 4 байта.

Цитата Сообщение от testuser2 Посмотреть сообщение
Какие сложности могут быть с 64бит?
В SAFEARRAYBOUND количество элементов тип ULONG, т.е. больше 4 байт туда нельзя записать. Соответственно максимальный адрес при 0м указателе который получится адресовать равен 0xFFFFFFFF * 4 = 0x3FFFFFFFC, однако размер адресного пространства гораздо больше - 63 бит.
1
Испарился
 Аватар для HackerVlad
1742 / 638 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
16.09.2023, 16:07
Цитата Сообщение от The trick Посмотреть сообщение
63 бит
Первый раз слышу, я думал бывает только 64 бит)))
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
16.09.2023, 16:07
Помогаю со студенческими работами здесь

конкатенация строк в excel через vba
Здравствуйте, столкнулся с проблемой. у меня есть 5 файлов excel с данными и один. куда надо вывести информацию, в одних и тех же ячейках...

Конкатенация и последующее копирование уникальных строк по условию
В файле есть 2 рабочих листа. Требуется с одного листа(List1), начиная с колонки С10, конкатенировать значения ячеек по строке до тех пор,...

Добавление записей массива из одной книги на лист другой + возможная конкатенация
Уважаемые форумчане! Возник вопрос касательно познания средств VBA в Excel'e. Идея такая: есть пользовательская форма, которую нужно...

Из символов одного текста с помощью стоковых функций о операция конкатенация получить другой текст
Из символов одного текста с помощью стоковых функций о операция конкатенация получить другой текст. Из "алгоритм " получить...

Конкатенация
Ребята как быть раньше было так : <img class="frame" src="<?php echo...


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Опции темы

Новые блоги и статьи
Благородство как наказание
Maks 24.04.2026
У хорошего человека отношения с женщинами всегда складываются трудно. А я человек хороший. Заявляю без тени смущения, потому что гордиться тут нечем. От хорошего человека ждут соответствующего. . .
Валидация и контроль данных табличной части документа перед записью
Maks 22.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в КА2. Задача: контроль и валидация данных табличной части документа перед записью с учетом регламента компании. . .
Отчёт о затраченных материалах за определенный период с макетом печатной формы
Maks 21.04.2026
Отчёт из решения ниже размещён в конфигурации КА2. Задача: разработка отчёта по затраченным материалам за определённый период, с возможностью вывода печатной формы отчёта с шапкой и подвалом. В. . .
Отчёт о спецтехнике находящейся в ремонте
Maks 20.04.2026
Отчёт из решения ниже размещен в конфигурации КА2. Задача: отобразить спецтехнику, которая на данный момент находится в ремонте. Есть нетиповой документ "Заявка на ремонт спецтехники" который. . .
Памятка для бота и "визитка" для читателей "Semantic Universe Layer (Слой семантической вселенной)"
Hrethgir 19.04.2026
Сгенерировано для краткого описания по случаю сборки и компиляции скелета серверного приложения. И пусть после этого скажут, что статьи сгенерированные AI - туфта и не интересно. И это не реклама -. . .
Запрет удаления строк ТЧ документа при определённом условии
Maks 19.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "Аккумуляторы", разработанного в конфигурации КА2. У данного документа есть ТЧ, в которой в зависимости от прав доступа. . .
Модель заражения группы наркоманов
alhaos 17.04.2026
Условия задачи сформулированы тут Суть: - Группа наркоманов из 10 человек. - Только один инфицирован ВИЧ. - Колются одной иглой. - Колются раз в день. - Колются последовательно через. . .
Мысли в слух. Про "навсегда".
kumehtar 16.04.2026
Подумалось тут, что наверное очень глупо использовать во всяких своих установках понятие "навсегда". Это очень сильное понятие, и я только начинаю понимать край его смысла, не смотря на то что давно. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru