Что нового

Script Правильная сортировка строк в ListView

IMStrelcov

CTPEJIbLLOB
Сообщения
157
Репутация
25
Версия AutoIt
3.3.14.5
Версия
0.1
Данный скрипт показывает более менее правильную сортировку в списке ListView
Прошу подсказать как можно ускорить код, так как время сортировки в 10000 строк в списке занимает около 30 секунд.
Может чегото не хватает или наоборот лишнее?
Так же можно предлагать свои примеры, идеи, на эту тему.

Сразу отвечу на пару вопросов которые могут возникнуть:
Зачем это нужно?
Всем, кто хоть раз копал инет по поводу алгоритмов сортировки, знает, что сортировка происходит по принципу или
1, 11, 9, 99, а, аа, в, вв или 1, 9, а, в, 11, 99, аа, вв.
Так вот в этом коде строки и цифры сортируются более менее адекватно, т.е.:
текст 1, текст 9, текст 11.
При сортировке стандартными способами было бы так:
текст 1, текст 11, текст 9.

Как отдается приоритет строкам и цифрам?
Каждая строка разбивается на группы последовательно идущих цифр, букв, и знаков, после чего строки сравниваются этими подгруппами.
Знаки имеют приоритет ниже чем цифры или буквы, поэтому строки начинающиеся на знаки всегда будут стоять выше всех строк.
Цифры имеют высший приоритет над знаками, но низший над буквами.
Буквы имеют высший приоритет над знаками и цифрами, и поэтому строки начинающиеся на букву будут стоять всегда ниже всех.

Почему в регулярном выражении не использовал [A-z] вместо перечисления букв?
Потому что при использовании [A-z] идет захват символа _ (нижнее подчеркивание), а это в моем понимании относится к знакам.

Будет ли дальше развиваться код в этом направлении?

Не знаю, все в ваших руках.
Я на это, что имею, убил более двух недель пока нашел и исправил косяки, еще месяц на реализацию в AutoIt-е алгоритмов разных сортировок, которые ни принесли нужного результата по скорости или требовали большего объема памяти для сортировки (только время отняло, хотя и опыта поднабрался).
Возможно в будущем и буду развивать эту тему, а пока времени нет.
Если есть толковые люди, а они есть, то прошу не стеснятся выкладывать свои идеи, обсуждать тему, а то форум смотрю вымирает, одни бото-кодеры развелись, которым то сделай или это.
Код:
#NoTrayIcon
#include <WindowsConstants.au3>
#include <GuiListView.au3>

$aArray = '@,@1,@11,@9,@99,@a,@zz,@z,@aa,@@1,@@99,@@9,@@11,@@zz,@@aa,@@a,@@z,@№,@№№,№1,№11,№@@,№@,№aa,№a,№zz,№z,№9,№99,№,№№9,№№a,№№1,№№,№№z,№№11,№№zz,№№99,№№aa,1zz,1z,1,1№,[email protected],1a,1№№,19,1aa,199,[email protected]@,[email protected],9a,91,9№№,[email protected]@,9,9№,911,9zz,9z,9aa,11aa,11a,11№,119,[email protected],11z,11№№,1199,11zz,11,[email protected]@,99№,99№№,99z,991,99zz,[email protected],99,9911,99aa,[email protected]@,99a,a,a№№,a№,a11,[email protected],a99,az,a1,azz,[email protected]@,a9,z99,z,z11,zaa,z1,z№№,[email protected],z9,z№,za,[email protected]@,aa,aazz,[email protected]@,aa99,aaz,[email protected],aa9,aa№№,aa11,aa1,aa№,zz1,zz№№,zz11,[email protected]@,zz,zzaa,zz№,zza,,[email protected],zz99,zz9'
$aArray = StringSplit($aArray, ',', 3)

$iWnd = GUICreate('Test ListView', 800, 600, -1, -1, $WS_MAXIMIZEBOX +$WS_MINIMIZEBOX +$WS_SIZEBOX +$WS_VISIBLE, $WS_EX_ACCEPTFILES)
$iListView = _GUICtrlListView_Create($iWnd, '', 10, 10, 780, 555, BitOR($LVS_REPORT, $LVS_SHOWSELALWAYS, $WS_CHILD, $WS_VISIBLE))
_GUICtrlListView_AddColumn($iListView, 'Sort', 760)

$iTime = TimerInit()
For $a=0 To UBound($aArray) -1
    _GUICtrlListView_AddItemSort($iListView, $aArray[$a])
Next
$iTime = TimerDiff($iTime)
ConsoleWrite('Time'&@TAB&@TAB&$iTime&@CRLF)

While 1
    Switch GUIGetMsg()
        Case -3
            ExitLoop
    EndSwitch
WEnd

Func _GUICtrlListView_AddItemSort(ByRef $_hWnd, ByRef $_sStrL)
    Local $_iIndex = 0
    Local $_iEnd = _GUICtrlListView_GetItemCount($_hWnd)
    Local $_iBegin = 1, $_aStrR, $_iCountC, $_iCountR, $_iA, $_iResult
    While 1
        $_sStrR = _GUICtrlListView_GetItemText($_hWnd, $_iIndex -1)
        $_iResult = StringCompare_($_sStrL, $_sStrR)
        If $_iResult = 0 Then ExitLoop
        If $_iBegin = $_iIndex Then
            If $_iResult < 0 Then ExitLoop
            $_iIndex = $_iEnd
            ContinueLoop
        ElseIf $_iIndex = $_iEnd Then
            If $_iResult > 0 Then $_iIndex += 1
            ExitLoop
        EndIf
        If $_iResult > 0 Then
            $_iBegin = $_iIndex
        Else
            $_iEnd = $_iIndex
        EndIf
        $_iIndex = Int(($_iEnd +$_iBegin) /2)
    WEnd
    _GUICtrlListView_InsertItem($_hWnd, $_sStrL, $_iIndex -1)
EndFunc

Func StringCompare_($_sStrL, $_sStrR)
    Local $_sChars = 'QWERTYUIOPLKJHGFDSAZXCVBNMmnbvcxzasdfghjklpoiuytrewqёЁА-я'
    Local $_aStrL = StringRegExp($_sStrL, '(['&$_sChars&']{1,}|[0-9]{1,}|[^0-9'&$_sChars&']{1,})', 3)
    If @error Then Return -1
    Local $_aStrR = StringRegExp($_sStrR, '(['&$_sChars&']{1,}|[0-9]{1,}|[^0-9'&$_sChars&']{1,})', 3)
    If @error Then Return 1
    Local $_iCountL = UBound($_aStrL) -1
    Local $_iCountR = UBound($_aStrR) -1
    Local $_iCount, $_iResult, $_iTypeL, $_iTypeR
    Do
        $_iTypeL = StringGetType_($_aStrL[$_iCount])
        $_iTypeR = StringGetType_($_aStrR[$_iCount])
        Switch $_iTypeL
            Case 0
                If $_iTypeR > 0 Then
                    $_iResult = -1
                Else
                    $_iResult = StringCompare($_aStrL[$_iCount], $_aStrR[$_iCount])
                EndIf
            Case 1
                If $_iTypeR < 1 Then
                    $_iResult = 1
                ElseIf $_iTypeR > 1 Then
                    $_iResult = -1
                ElseIf Number($_aStrL[$_iCount]) > Number($_aStrR[$_iCount]) Then
                    $_iResult = 1
                ElseIf Number($_aStrL[$_iCount]) < Number($_aStrR[$_iCount]) Then
                    $_iResult = -1
                Else
                    $_iResult = 0
                EndIf
            Case 2
                If $_iTypeR < 2 Then
                    $_iResult = 1
                Else
                    $_iResult = StringCompare($_aStrL[$_iCount], $_aStrR[$_iCount])
                EndIf
        EndSwitch
        $_iCount += 1
    Until ($_iCount > $_iCountL) Or ($_iCount > $_iCountR) Or ($_iResult <> 0)
    If Not $_iResult Then
        If $_iCountL < $_iCountR Then Return -1
        If $_iCountL > $_iCountR Then Return 1
    EndIf
    Return $_iResult
EndFunc

Func StringGetType_(ByRef $_sStr)
    If StringIsAlpha($_sStr) Then Return 2
    If StringIsDigit($_sStr) Then Return 1
    Return 0
EndFunc
 

joiner

Модератор
Локальный модератор
Сообщения
3 362
Репутация
586
тема для рабочих(работающих, готовых) проектов. общие вопросы в другой теме
 
Верх