Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.93/57: Рейтинг темы: голосов - 57, средняя оценка - 4.93
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18030 / 7733 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16

Сортировка словаря методом реконструкции

13.04.2014, 01:43. Показов 12036. Ответов 47

Студворк — интернет-сервис помощи студентам
Посмотрите, пожалуйста, может существует более оптимальный алгоритм.

Здесь я создаю 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
28
'Сортировка словаря методом вставок -> исходный словарь реконструируется
Sub SpecialSortDict(inDict)
    Dim arrPos: arrPos = inDict.keys                    'Инициализация массива позиций ключей словаря
    Dim arrTemp: arrTemp = inDict.Items                 'Виртуализация значений словаря
 
    Dim i, j, xItem
    For i = 1 To UBound(arrTemp)                        'Сортировка методом вставок
        For j = i To 1 Step -1
            If arrTemp(j) < arrTemp(j - 1) Then
                xItem = arrTemp(j)                      'Обмен значений
                arrTemp(j) = arrTemp(j - 1)
                arrTemp(j - 1) = xItem
                xItem = arrPos(j)                       'Обмен ключей
                arrPos(j) = arrPos(j - 1)
                arrPos(j - 1) = xItem
            Else
                Exit For
            End If
        Next
    Next
 
    Dim virtDict: Set virtDict = CreateObject("Scripting.Dictionary")
    For i = 0 To UBound(arrPos)                         'Расставляем значения в виртуальный словарь согласно массива ключей
        virtDict.Add arrPos(i), inDict(arrPos(i))
    Next
 
    Set inDict = virtDict
End Sub
Пример вызова:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Option Explicit
 
Sub main()
    Dim oScr: Set oScr = CreateObject("Scripting.Dictionary")
    
    oScr.Add "c", 8
    oScr.Add "aa", 1
    oScr.Add "bb", 3
    oScr.Add "a", 2
    oScr.Add "i", 4
    
    SpecialSortDict oScr
    
    Dim key
    For Each key In oScr.keys
        Debug.Print key & " - " & oScr(key)
    Next
    
End Sub
Переменные изначально нетипизированны. Код ориентирован на VBScript.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
13.04.2014, 01:43
Ответы с готовыми решениями:

Составить алгоритм и программу определения самых старых зданий, подлежащих реконструкции
Имеется список 60-ти зданий города, подлежащих реконструкции. Сведения о каждом здании содержат название микрорайона, улицу, номер дома и...

Сортировка словаря
Функция которая возвращает словарь. Но бывает что возвращает его не в том порядке в котором задавался. def multiply(vector, num): ...

Сортировка словаря
Всем привет. Есть словарь: babynames = { 'София, Софья': { 2012: ', 2010: ', 2005: ',

47
 Аватар для Антихакер32
1201 / 473 / 46
Регистрация: 06.01.2014
Сообщений: 1,797
Записей в блоге: 19
13.04.2014, 11:10
Я думаю нужно
паралельно создать второй словарь Dictionary полный клон
со скопированными элементами первого

у словоря есть ключи Keys или Items ...это массивы

в зависимости от того какие элементы нужно упорядочить

можно воспользоваться быстрой сортировкой

Кликните здесь для просмотра всего текста
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
Option Explicit
'
'Быстрая соротировка различных типов с возможностью подстройки
'© FelixMacintosh (Антихакер32™)
'
Public Enum F_Compare
    [Числовые элементы] = 0
    [Текстовые элементы] = 1
    [По убыванию] = 2
    [Игнорировать регистр] = 4
    [Учёт длины элементов] = 8
End Enum
Private FMax As Long, j() As String, n&, s$
 
Public Function Find&(List As Variant, ByVal Elm As Variant, _
Optional Flag As F_Compare)
    'Бинарный поиск
    'Возврат положительного числа найденной позиции элемента в списке
    'Арг: Список // Элемент // Флаги сравнений
    Find = LBound(List)
    FMax = UBound(List)
 
1
    While FMax > Find
        Find = Fix((Find + FMax) / 2)
        On Compare(Elm, List(Find), Flag) + 1 GoTo 2, 3
        FMax = Find - 1
        GoTo 1
2
        Exit Function
3
        Find = Find + 1
    Wend
    Find = -1
End Function
 
Public Function Sort(List As Variant, Flag As F_Compare, Optional ByVal Min&, Optional ByVal Max& = -1) As Variant
    'Быстрая сортировка
    'Арг: Список // Флаги сравнений // [Нижний индекс] // [Верхний индекс]
    'Возвращаемое значение: Отсортированный список
    If Max < 0 Then Max = UBound(List)
 
    If TypeName(List) = "String()" Then
        j = List
        Sort_Str j, Flag, Min, Max
        Sort = j
    Else
        Sort = List
        Sort_Var Sort, Flag, Min, Max
    End If
End Function
 
Private Sub Sort_Str(List() As String, Flag As F_Compare, Min&, Max&)
    'Рекурсивный алгоритм быстрой сортировки
    Dim i1&, i2&
    If Max - Min < 1 Then Exit Sub 'Пройден весь список
    n = Fix((Max - Min + 1) / 5 + Min) 'Выбрать разделяющее значение.
    s = List(n)
    List(n) = List(Min) 'Переместить его вперед.
    i1 = Min: i2 = Max
 
    Do
 
        While Compare(List(i2), s, Flag) >= 0 'Просмотр сверху вниз от i2 до значения >= s
            i2 = i2 - 1
            If i2 <= i1 Then List(i1) = s: Exit Do
        Wend
        List(i1) = List(i2) 'Поменять местами значения i1 и i2.
        '-----------
        i1 = i1 + 1 'Просмотр снизу вверх от i1 до значения < s.
 
        While Compare(List(i1), s, Flag) < 0
            i1 = i1 + 1
            If i1 >= i2 Then i1 = i2: List(i2) = s: Exit Do
        Wend
        List(i2) = List(i1) 'Поменять местами значения i1 и i2.
    Loop
    '---------------------------------Сортировать два подсписка.
    On Error GoTo 1
 
    While List(i1) = List(i1 - 1) 'Сокращение диапазона поиска для Max
        i1 = i1 - 1
    Wend
    Sort_Str List, Flag, Min, i1
1
    On Error GoTo 2
 
    While List(i1) = List(i1 + 1) 'Сокращение диапазона поиска для Min
        i1 = i1 + 1
    Wend
    Sort_Str List, Flag, i1 + 1, Max
2
End Sub
 
Private Sub Sort_Var(List As Variant, Flag As F_Compare, Min&, Max&)
    'Рекурсивный алгоритм быстрой сортировки
    Dim i1&, i2&
    Static n&, v As Variant
    If Max - Min < 1 Then Exit Sub 'Пройден весь список
    n = Fix((Max - Min + 1) / 5 + Min) 'Выбрать разделяющее значение.
    v = List(n)
    List(n) = List(Min) 'Переместить его вперед.
    i1 = Min: i2 = Max
 
    Do
 
        While Compare(List(i2), v, Flag) >= 0 'Просмотр сверху вниз от i2 до значения >= v
            i2 = i2 - 1
            If i2 <= i1 Then List(i1) = v: Exit Do
        Wend
        List(i1) = List(i2) 'Поменять местами значения i1 и i2.
        '-----------
        i1 = i1 + 1 'Просмотр снизу вверх от i1 до значения < v.
 
        While Compare(List(i1), v, Flag) < 0
            i1 = i1 + 1
            If i1 >= i2 Then i1 = i2: List(i2) = v: Exit Do
        Wend
        List(i2) = List(i1) 'Поменять местами значения i1 и i2.
    Loop
    '---------------------------------Сортировать два подсписка.
    On Error GoTo 1
 
    While List(i1) = List(i1 - 1) 'Сокращение диапазона поиска для Max
        i1 = i1 - 1
    Wend
    Sort_Var List, Flag, Min, i1
1
    On Error GoTo 2
 
    While List(i1) = List(i1 + 1) 'Сокращение диапазона поиска для Min
        i1 = i1 + 1
    Wend
    Sort_Var List, Flag, i1 + 1, Max
2
End Sub
 
Public Function Compare&(Elm1 As Variant, Elm2 As Variant, ByVal Flag As F_Compare)
    'Улучшенная функция сравнения
    If Elm1 = Elm2 Then Exit Function
    On Flag GoTo 1, 2, 3, 2, 5, 2, 7, 2, 9, 2, 11, 2, 13, 2, 15
    Compare = (CDbl(Elm1) < CDbl(Elm2)) * 2 + 1
    Exit Function
2
    Compare = (CDbl(Elm2) < CDbl(Elm1)) * 2 + 1
    Exit Function
1
    Compare = StrComp(Elm1, Elm2, vbBinaryCompare)
    Exit Function
3
    Compare = StrComp(Elm2, Elm1, vbBinaryCompare)
    Exit Function
5
    Compare = StrComp(Elm1, Elm2, vbTextCompare)
    Exit Function
7
    Compare = StrComp(Elm2, Elm1, vbTextCompare)
    Exit Function
9
    Compare = Sgn(LenB(Elm1) - LenB(Elm2))
    If Compare = 0 Then Compare = StrComp(Elm1, Elm2, vbBinaryCompare)
    Exit Function
11
    Compare = Sgn(LenB(Elm2) - LenB(Elm1))
    If Compare = 0 Then Compare = StrComp(Elm2, Elm1, vbBinaryCompare)
    Exit Function
13
    Compare = Sgn(LenB(Elm1) - LenB(Elm2))
    If Compare = 0 Then Compare = StrComp(Elm1, Elm2, vbTextCompare)
    Exit Function
15
    Compare = Sgn(LenB(Elm2) - LenB(Elm1))
    If Compare = 0 Then Compare = StrComp(Elm2, Elm1, vbTextCompare)
    Exit Function
End Function


затем переписать значения в первый словарь
вызывая его связанные элементы из второго ранее клонированного

Добавлено через 15 минут
Напомню флагами можно воспользоваться так ..
Visual Basic
1
flags = [Текстовые элементы] Or [По убыванию] Or  [Игнорировать регистр]
ну думаю код для того чтоб клонировать словарь вам не надо подсказывать
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,844
Записей в блоге: 79
13.04.2014, 11:32
Смысл сортировки? Чтобы в For each по порядку шли?
0
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18030 / 7733 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
13.04.2014, 16:09  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
Смысл сортировки? Чтобы в For each по порядку шли?
Да, распечатка словаря во внешний csv файл.

FelixMacintosh, спасибо. Думаю, в границах моей задачи, мой код будет по-компактнее
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,844
Записей в блоге: 79
13.04.2014, 16:14
Цитата Сообщение от Dragokas Посмотреть сообщение
Да, распечатка словаря во внешний csv файл.
Тогда можно упростить реализуя IEnumVariant, либо изменять ссылки в ассоциативном массиве Dictonary (хак, так что может не работать на разных версиях, хотя не встречал таких).
0
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38161 / 21096 / 4306
Регистрация: 12.02.2012
Сообщений: 34,679
Записей в блоге: 14
13.04.2014, 16:28
Dragokas, а велики ли объемы данных в словаре? Количество больше 32 тыс?
0
 Аватар для Антихакер32
1201 / 473 / 46
Регистрация: 06.01.2014
Сообщений: 1,797
Записей в блоге: 19
13.04.2014, 17:02
Цитата Сообщение от Catstail Посмотреть сообщение
Количество больше 32 тыс?
а почему вы спрашиваете?, чувствуется подвох ..
наверное есть ограничения какие-то ...

Добавлено через 6 минут
Цитата Сообщение от Dragokas Посмотреть сообщение
FelixMacintosh, спасибо. Думаю, в границах моей задачи, мой код будет по-компактнее
там достаточно выдернуть из моего модуля только функцию сортировки Sort_Str

Цитата Сообщение от The trick Посмотреть сообщение
хак, так что может не работать на разных версиях, хотя не встречал таких
вот именно что хак может не сработать ...
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,844
Записей в блоге: 79
13.04.2014, 17:04
Цитата Сообщение от FelixMacintosh Посмотреть сообщение
вот именно что хак может не сработать ...
Получение ключей коллекции тоже хак, однако работает везде. Это очень малая вероятность что не будет работать. Для этого я и написал что нужна реализация IEnumVariant, хотя не понятно можно создать класс-обертку и в ней хранить отсортированные ключи и индексы уже, тогда ничего не надо будет вообще делать.
0
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38161 / 21096 / 4306
Регистрация: 12.02.2012
Сообщений: 34,679
Записей в блоге: 14
13.04.2014, 17:08
Цитата Сообщение от FelixMacintosh Посмотреть сообщение
чувствуется подвох ..
наверное есть ограничения какие-то ...
- я имел в виду, что в VB у Listbox есть свойство "sorted". Но в ListBox нельзя загрузить более 32 тыс. строк
1
 Аватар для Антихакер32
1201 / 473 / 46
Регистрация: 06.01.2014
Сообщений: 1,797
Записей в блоге: 19
13.04.2014, 17:11
я эксперементировал со словарем еще очень давно простая сортировка и перезапись значений производится достаточно быстро .. без всяких обёрток и хаков уверяю вас
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,844
Записей в блоге: 79
13.04.2014, 17:13
Цитата Сообщение от FelixMacintosh Посмотреть сообщение
я эксперементировал сл словарем еще очень давно простая сортировка и перезапись значений производится достаточно быстро .. без всяких обёрток и хаков уверяю вас
Я уверяю тебя что это дольше (во много раз) чем непосредственно хранить уже упорядоченные ключи.
0
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18030 / 7733 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
13.04.2014, 19:35  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
Тогда можно упростить реализуя IEnumVariant, либо изменять ссылки в ассоциативном массиве Dictonary
То, что Вы написали мне совершенно не понять, к сожалению. Про ссылки только поверхностно понимаю.
Предполагается вмешательство в структуру словаря через API?
Цитата Сообщение от Catstail Посмотреть сообщение
Dragokas, а велики ли объемы данных в словаре? Количество больше 32 тыс?
Задачу свою уже выполнил (до сотни эл-тов). Может и криво. Остальное интересует чисто теоретически.
Сам утиль.
Цитата Сообщение от The trick Посмотреть сообщение
Я уверяю тебя что это дольше (во много раз) чем непосредственно хранить уже упорядоченные ключи.
Интересное наблюдение. Нужно провести тесты.
1
 Аватар для Антихакер32
1201 / 473 / 46
Регистрация: 06.01.2014
Сообщений: 1,797
Записей в блоге: 19
13.04.2014, 19:44
я и не знал что здесь на форуме есть Полезные VBS скрипты ...
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,844
Записей в блоге: 79
13.04.2014, 19:44
Про IEnumVariant поверхностно можешь почитать здесь. Чтобы добраться до словаря нужно анализировать его структуру, я как-то поверхностно это делал здесь.

Не по теме:

Dragokas, кстати давай на "ты" ;)

1
13.04.2014, 20:11  [ТС]

Не по теме:

Это мое проклятие. Всегда могу называть по-разному. Прошу не обижаться.

0
 Аватар для Антихакер32
1201 / 473 / 46
Регистрация: 06.01.2014
Сообщений: 1,797
Записей в блоге: 19
13.04.2014, 20:21
только недавно понял что скрипты очень легко можно запускать из
любого VB6 проекта ... Set objScript = CreateObject("MSScriptControl.ScriptCont rol")

это к примеру текст vbs можно хранить у себя в закутках и запускать ...
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,844
Записей в блоге: 79
14.04.2014, 01:42
Лучший ответ Сообщение было отмечено The trick как решение

Решение

Немного посидел над "словарем", кое-что стало проясняться. Вот например например код получения элементов по ключу из словаря.
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
Option Explicit
 
Private Declare Function GetMem4 Lib "msvbvm60" (Src As Any, Dst As Any) As Long
Private Declare Function VarBstrCmp Lib "oleaut32" (ByVal bstrLeft As Long, ByVal bstrRight As Long, ByVal lcid As Long, ByVal dwFlags As Long) As Long
Private Declare Sub VariantCopy Lib "oleaut32.dll" (pvargDest As Any, pvargSrc As Any)
 
Private Sub Form_Load()
    Dim Z As Scripting.Dictionary, p As String, i As Long
    
    Set Z = New Dictionary
    
    Z.CompareMode = TextCompare
 
    For i = 0 To 9999
        Z.Add "Key" & CStr(i), "Item" & CStr(i)
    Next
    
    'p = Z.Item("Key2")
    
    p = GetItem(Z, "Key788")
    
    MsgBox p
    
End Sub
 
' Получить элемент по ключу
Private Function GetItem(Dic As Dictionary, Key As String) As Variant
    Dim Hash As Long, pHTbl As Long, pHItem As Long, lcid As Long, cmp As Long, iKey As Long
    ' Получаем lcid
    GetMem4 ByVal ObjPtr(Dic) + &H30, lcid
    ' Вычисляем хэш
    Hash = HashVal(Dic, Key)
    ' Получаем указатель на хэш-таблицу
    GetMem4 ByVal ObjPtr(Dic) + &H24, pHTbl
    ' Получаем указатель элемента в хэш-таблице
    GetMem4 ByVal pHTbl + Hash * 4, pHItem
    ' Если есть такой элемент
    Do While pHItem
        ' Сравниваем значение ключа в таблице с заданым ключем
        GetMem4 ByVal pHItem + 16, iKey
        Select Case VarBstrCmp(StrPtr(Key), iKey, lcid, Dic.CompareMode)
        Case 1: VariantCopy GetItem, ByVal pHItem + &H18: Exit Function
        Case Else: GetMem4 ByVal pHItem + &H28, pHItem ' Получаем указатель на следующую запись в таблице
        End Select
    Loop
    ' Нет такого элемента
End Function
 
Private Function HashVal(Dic As Dictionary, ByVal S As String) As Long
    Dim i As Long, ch As Currency, res As Long, cres As Currency, Div As Long
    If Dic.CompareMode = TextCompare Then S = StrConv(S, vbLowerCase)
    ' Извращения с Currency, т.к. в VB нет UINT32 и циклической арифметики
    For i = 0 To Len(S) - 1
        ch = AscW(Mid$(S, i + 1, 1)) / 10000
        cres = CCur(res) / 10000 * 17 + ch
        GetMem4 cres, res
    Next
    cres = 0: GetMem4 res, cres
    ch = cres * 10000
    GetMem4 ByVal ObjPtr(Dic) + &H28, Div   ' Константа
    HashVal = (ch - (Int(ch / Div) * Div))
End Function
Добавлено через 27 минут
Получить список значений
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
' ObjPtr+&H18 (Dic.Count)
' Получить список элементов
Private Function Items(Dic As Dictionary) As Variant
    Dim pItm As Long, loc() As Variant, i As Long
    
    ReDim loc(Dic.Count - 1)
    ' Указатель на первый элемент списка
    GetMem4 ByVal ObjPtr(Dic) + &H1C, pItm
    ' Проход по элементам списка
    Do
        VariantCopy loc(i), ByVal pItm + &H18
        ' Следующий элемент
        GetMem4 ByVal pItm + 4, pItm
        i = i + 1
    Loop While pItm
    
    Items = loc
End Function
Добавлено через 50 минут
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
' Получить элемент по индексу
Private Function GetByIndex(Dic As Dictionary, ByVal Index As Long) As Variant
    Dim pItm As Long
    
    If Dic.Count = 0 Then Exit Function
    
    ' Указатель на первый элемент списка
    GetMem4 ByVal ObjPtr(Dic) + &H1C, pItm
    ' Проход по элементам списка
    Do While CBool(Index) And pItm
        ' Следующий элемент
        GetMem4 ByVal pItm + 4, pItm
        Index = Index - 1
    Loop
 
    VariantCopy GetByIndex, ByVal pItm + &H18
End Function
Добавлено через 14 минут
Получить сразу ключи и их значения
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Private Type DicItem
    Key As Variant
    Item As Variant
End Type
Private Sub GetPair(Dic As Dictionary, Out() As DicItem)
    Dim pItm As Long, i As Long
    
    If Dic.Count = 0 Then Exit Sub
    
    ReDim Out(Dic.Count - 1)
    ' Указатель на первый элемент списка
    GetMem4 ByVal ObjPtr(Dic) + &H1C, pItm
    ' Проход по элементам списка
    Do
        VariantCopy Out(i).Item, ByVal pItm + &H8
        VariantCopy Out(i).Key, ByVal pItm + &H18
        ' Следующий элемент
        GetMem4 ByVal pItm + 4, pItm
        i = i + 1
    Loop While pItm
End Sub
Добавлено через 1 час 29 минут
Сортировка методом вставок на месте (то что ты искал видимо (можно еще оптимизировать))
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
' Сортировка методом вставок на месте (сортируются значения)
Private Sub Sort(Dic As Dictionary)
    Dim lh As Long, e As Long, se As Long, bs As Long, be As Long, s As Long, lcid As Long
    GetMem4 ByVal ObjPtr(Dic) + &H30, lcid
    ' Указатель на первый элемент списка
    GetMem4 ByVal ObjPtr(Dic) + &H1C, lh
    be = lh
    GetMem4 ByVal lh + 4, e
    ' Проход
    Do While e
        s = 0: se = lh: bs = 0
        Do Until se = e
            If VarCmp(e + &H18, se + &H18, lcid, 0) < 2 Then
                GetMem4 ByVal e + &H4, ByVal be + &H4
                GetMem4 se, ByVal e + &H4
                If bs Then
                    GetMem4 e, ByVal bs + &H4
                Else: lh = e
                End If
                GetMem4 ByVal be + &H4, e
                bs = 0: s = 1
                Exit Do
            Else
                bs = se
                GetMem4 ByVal se + &H4, se
            End If
        Loop
        If s = 0 Then
            be = e
            GetMem4 ByVal e + &H4, e
        End If
    Loop
    GetMem4 lh, ByVal ObjPtr(Dic) + &H1C
End Sub
Чтобы сортировать ключи нужно вместо &H18 писать &H8
6
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,844
Записей в блоге: 79
14.04.2014, 06:07
Лучший ответ Сообщение было отмечено The trick как решение

Решение

Все нижеописанное относится к моей библиотеке scrrun. Возможно в других версиях это не будет работать, хотя вряд ли.
В общем более-менее все стало понятно. Словарь представляет из себя хэш-таблицу элементы которой содержат указатели на элементы односвязного списка. Каждый элемент представляет из себя структуру длиной 48 байт вида
Visual Basic
1
2
3
4
5
6
7
8
Private Type DictionaryItem
    pInterface As Long      '0
    pNext As Long           '4
    Key As Variant          '8
    Item As Variant         '18
    PointerToHash As Long   '28
    Reserved As Long        '2C
End Type
Первое поле содержит указатель на VTable (какую не выяснял)
pNext - содержит указатель на следующий элемент списка (порядковый, в том виде как он добавлялся, и в каком будет выводится через For each)
Key и Item это и так понятно
PointerToHash содержит указатель на следующий элемент имеющий такое же значение хэш (коллизия).
Для режима TextCompare ключи хранятся в нижнем регистре.
Для ускорения добавления значения в список, объект Dictionary хранит указатель на последний добаленый элемент по смещению &H20. &H18 - количество элементов.
________________________________________ ________________________________________ ____________________________
Закончу свои исследования небольшим проектом где реализованы дополнительные возможности работы со словарем.
  • Sort - сортировка по ключам или по значениям без создания дополнительных массивов, все походит внутри объекта. Кто знает эффективный алгоритм сортировки односвязного списка можно сюда включить. (ранее опубликованная версия имеет баг).
  • GetPair - заполняет массив значениями ключей с их значениями.
  • GetIndexByKey - получить индекс (позицию) в односвязном списке по ключу. Этот индекс будет равен индексу в For each.
  • GetKeyByIndex - получить ключ по индексу.
  • GetByIndex - получить значение по индексу
  • Items - эквивалентно одноименному свойству, только работая напрямую со списком.
  • Exist - эквивалентно одноименному свойству, только работая напрямую со списком.
  • GetItem - эквивалентно свойству Item(), только работая напрямую со списком.
  • HashVal - эквивалентно одноименному свойству.
В программе можно просматривать расширенную информацию о словаре, сортировать, просматривать количество коллизий в таблице.
Миниатюры
Сортировка словаря методом реконструкции  
Вложения
Тип файла: rar DicViewer.rar (13.7 Кб, 60 просмотров)
5
 Аватар для Антихакер32
1201 / 473 / 46
Регистрация: 06.01.2014
Сообщений: 1,797
Записей в блоге: 19
14.04.2014, 07:25
Анатолий !
Спешу тебя обрадовать у меня все работает так как надо
только вот почему такой примитивный метод сортировки (вставками ?)
Миниатюры
Сортировка словаря методом реконструкции  
0
 Аватар для Антихакер32
1201 / 473 / 46
Регистрация: 06.01.2014
Сообщений: 1,797
Записей в блоге: 19
14.04.2014, 09:55
Хотя я как всегда сделал всё гораздо прощще ! ✰

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
Option Explicit
'
'Сортировка словаря !
'© FelixMacintosh (Антихакер32™)
'
Const Elemens = 100
Dim Dic1 As Dictionary
Dim Dic2 As Dictionary
Dim WithEvents Picture1 As PictureBox
Dim WithEvents Picture2 As PictureBox
Dim WithEvents Command1 As CommandButton
 
Private Sub Command1_Click()
    Const r = vbNullChar & "[Разделяющее значение]" & vbNullChar
    Dim Keys, j$(), f&, v As Variant, p(1) As PictureBox
    CreateDictionary
    Keys = Dic1.Keys
    For f = 0 To Dic1.Count - 1
        Keys(f) = Keys(f) & r & Dic1.Item(Keys(f))
    Next
    Call SortStr(Keys, Dic1.CompareMode, 0, UBound(Keys))
    Dic2.RemoveAll
    For f = 0 To Dic1.Count - 1
        j = Split(Keys(f), r)
        Dic2.Add j(0), j(1)
    Next
    '---------------------------------------------------------------------------------------
    Set p(0) = Picture1: Set p(1) = Picture2
    For f = 0 To 1: p(f).Cls: Next
    p(0).Print vbTab; "Исходный список Dic1"
    p(1).Print vbTab; "Отсортированный список Dic2"
    For f = 0 To 1: p(f).Print String(1000, "*"): Next
    For Each v In Dic1
        Picture1.Print vbTab; v; vbTab; , "="; vbTab; Dic1(v)
    Next
    For Each v In Dic2 'Абсолютное соответствие !
        Picture2.Print vbTab; v; vbTab; , "="; vbTab; Dic2(v); vbTab; "Dic1(" & v & ") = " & Dic1(v)
    Next
End Sub
 
Private Sub Form_Initialize()
    Set Dic1 = CreateObject("Scripting.Dictionary")
    Dic1.CompareMode = 1
    Set Dic2 = CreateObject("Scripting.Dictionary")
    Dic2.CompareMode = 1
End Sub
 
Private Sub Form_Load()
    Set Picture1 = Controls.Add("VB.PictureBox", "Picture1")
    Set Picture2 = Controls.Add("VB.PictureBox", "Picture2")
    Set Command1 = Controls.Add("VB.CommandButton", "Command1")
    Picture1.Visible = True: Picture2.Visible = True
    Command1.Caption = "Запустить !"
    Command1.Visible = True
End Sub
 
Private Sub Form_Resize()
    Const c1 = 5, c2 = 20
    Dim twx&, w1&
    twx = c1 * Screen.TwipsPerPixelX
    Form1.WindowState = 2
    w1 = Me.ScaleWidth / 2
    Picture1.Move 0, 0, w1, Me.ScaleHeight
    Picture2.Move w1 + twx, 0, w1 - twx, Me.ScaleHeight
    Command1.Move w1 - c2 * twx, 0, c2 * twx, c1 * twx
    Command1.ZOrder 0
End Sub
 
Private Sub CreateDictionary()
 
    Dim s$, j$(), f&, f1&, i&
    Randomize Timer
    s = vbNullString
    For f = 1 To Elemens
        For f1 = 1 To 1 + Fix(Rnd * 10)
            s = s & Chr(65 + Fix(Rnd * 26))
            i = i + 1: Mid(s, i, 1) = IIf(Fix(Rnd * 2), UCase(Mid(s, i, 1)), LCase(Mid(s, i, 1)))
        Next
        s = s & " ": i = i + 1
    Next
    j = Split(s): ReDim Preserve j(UBound(j) - 1)
    
    Dic1.RemoveAll
    For f = 0 To UBound(j)
        While Dic1.Exists(j(f))
            s = "": i = 0
            For f1 = 1 To 1 + Fix(Rnd * 10)
                s = s & Chr(65 + Fix(Rnd * 26))
                i = i + 1: Mid(s, i, 1) = IIf(Fix(Rnd * 2), UCase(Mid(s, i, 1)), LCase(Mid(s, i, 1)))
            Next
            j(f) = s
        Wend
        Dic1.Add j(f), f
    Next
End Sub
 
Private Sub SortStr(List As Variant, Compare&, Min&, Max&)
    'Рекурсивный алгоритм быстрой сортировки
    Dim i1&, i2&, n&, s$
    If Not IsArray(List) Then Err.Raise 13
    If Max - Min < 1 Then Exit Sub 'Пройден весь список
    n = Fix((Max - Min + 1) / 5 + Min) 'Выбрать разделяющее значение.
    s = List(n)
    List(n) = List(Min) 'Переместить его вперед.
    i1 = Min: i2 = Max
 
    Do
 
        While StrComp(List(i2), s, Compare) >= 0 'Просмотр сверху вниз от i2 до значения >= s
            i2 = i2 - 1
            If i2 <= i1 Then List(i1) = s: Exit Do
        Wend
        List(i1) = List(i2) 'Поменять местами значения i1 и i2.
        '-----------
        i1 = i1 + 1 'Просмотр снизу вверх от i1 до значения < s.
 
        While StrComp(List(i1), s, Compare) < 0
            i1 = i1 + 1
            If i1 >= i2 Then i1 = i2: List(i2) = s: Exit Do
        Wend
        List(i2) = List(i1) 'Поменять местами значения i1 и i2.
    Loop
    '---------------------------------Сортировать два подсписка.
    On Error GoTo 1
 
    While List(i1) = List(i1 - 1) 'Сокращение диапазона поиска для Max
        i1 = i1 - 1
    Wend
    SortStr List, Compare, Min, i1
    
1
    On Error GoTo 2
 
    While List(i1) = List(i1 + 1) 'Сокращение диапазона поиска для Min
        i1 = i1 + 1
    Wend
    SortStr List, Compare, i1 + 1, Max
2
End Sub
Миниатюры
Сортировка словаря методом реконструкции  
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
14.04.2014, 09:55
Помогаю со студенческими работами здесь

Сортировка словаря
##Дан словарь. Помогите остортировать его по значению Номер Dictionary = {'№':,'1':,'2':,'3':} print...

Сортировка словаря
database = { &quot;Группа1&quot;:, , ], &quot;Группа2&quot;:, ] } def cout2(groupname): for key in...

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

Сортировка словаря по ключу
Как отсортировать Dictionary &lt;int, Vector3&gt; по ключу, по возрастанию? Метода Sort() для словаря так сходу не нашёл. Надо компаратор...

Сортировка ключей словаря
Здравствуйте:) Существует словарь следующего вида: {'35': 1, '45': 2, '56': 3, '76': 4, '24': 5} Нужно отсортировать ключи данного...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru