Что нового

Сортировка массива по пути к файлу

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Вот пример:

Код:
#include <Array.au3>

Dim $aArray[5] = ['Other\A.jpg', 'Other\B\A.jpg', 'Other\B\B.jpg', 'Other\C.jpg', 'Other\B\C.jpg']

_ArraySort($aArray, 0, 1)
_ArrayDisplay($aArray)


Результат:

Код:
Other\A.jpg
Other\B\A.jpg
Other\B\B.jpg
Other\B\C.jpg
Other\C.jpg

А нужно:

Код:
Other\A.jpg
Other\C.jpg
Other\B\A.jpg
Other\B\B.jpg
Other\B\C.jpg

т.е сортировать нужно с учётом уровня путей к файлам.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
На ум приходит только такой вариант:

Код:
#include <Array.au3>

Dim $aArray[5] = ['Other\A.jpg', 'Other\B\A.jpg', 'Other\B\B.jpg', 'Other\C.jpg', 'Other\B\C.jpg']

_ArraySortEx($aArray)
_ArrayDisplay($aArray)

Func _ArraySortEx(ByRef $avArray)
	For $i = 0 To UBound($avArray) - 1
		StringReplace($avArray[$i], '\', '')
		$avArray[$i] = @extended & '_' & $avArray[$i]
	Next
	
	_ArraySort($avArray, 0, 1)
	
	For $i = 0 To UBound($avArray) - 1
		$avArray[$i] = StringRegExpReplace($avArray[$i], '^\d+_', '')
	Next
EndFunc


Но тут есть проблема, вот такой массив сортируется немного не правильно:
Код:
Dim $aArray[5] = ['Other\A.jpg', 'New\B\A.jpg', 'Other\B\B.jpg', 'Other\C.jpg', 'Other\B\C.jpg']

все Other должны идти подряд.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
CreatoR [?]
все Other должны идти подряд.
Вы уж, батенька, определитесь ;D
По первому вопросу у меня созрело вот такое решение (оно похоже на ваше).
Код:
#include <Array.au3>

Dim $aArray[5] = ['Other\A.jpg', 'Other\B\A.jpg', 'Other\B\B.jpg', 'Other\C.jpg', 'Other\B\C.jpg']

_ArrayDisplay($aArray, 1)
_BubbleSort($aArray)
_ArrayDisplay($aArray, 2)

Func _TmpSort(ByRef $aArray)

	Local $aTmp[UBound($aArray)][2]

	For $i = 0 To UBound($aArray) -1
		$aPath = StringSplit($aArray[$i], "\")
		$aTmp[$i][0] = $aArray[$i]
		$aTmp[$i][1] = $aPath[0] & $aPath[$aPath[0]]
	Next

	$aArray = $aTmp
EndFunc

Func _BubbleSort(ByRef $aArray)

	_TmpSort($aArray)

	For $i = 0 To UBound($aArray) -1
		For $j = ($i+1) To UBound($aArray)-1
			If ($aArray[$j][1] < $aArray[$i][1]) Then
					$sTmp1 = $aArray[$i][0]
					$sTmp2 = $aArray[$i][1]
					$aArray[$i][0] = $aArray[$j][0]
					$aArray[$i][1] = $aArray[$j][1]
					$aArray[$j][0] = $sTmp1
					$aArray[$j][1] = $sTmp2
			EndIf
		Next
	Next

	ReDim $aArray[UBound($aArray)][1]
EndFunc
P.S. Пример не учитывает ваше второе пожелание
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Garrett [?]
Вы уж, батенька, определитесь
Я определился, они должны идти подряд, но должен сохранятся уровень вложенности путей.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
CreatoR [?]
они должны идти подряд, но должен сохранятся уровень вложенности путей.
То есть, так?
Код:
Other\A.jpg
Other\C.jpg
Other\B\B.jpg
Other\B\C.jpg
New\B\A.jpg
 

СН3СН2ОН

Знающий
Сообщения
78
Репутация
12
Если подойдет то потом просто из 2D->1D массив
Код:
#include <Array.au3>

Dim $aArray[5] = ['Other\A.jpg', 'Other\B\A.jpg', 'Other\B\B.jpg', 'Other\C.jpg', 'Other\B\C.jpg']

Global $aArray_mod[5][3]

For $i = 0 To UBound($aArray) - 1
	$aArray_mod[$i][1] = StringRegExpReplace($aArray[$i], '^(?:.*\\)([^\\]*?)$', '\1')
	$aArray_mod[$i][0] = StringRegExpReplace($aArray[$i], '^(.*)(?:\\.*?)$', '\1')
Next
_ArraySort($aArray_mod, 0, Default, Default, 0)

Local $k = 0
For $i = 0 To UBound($aArray) - 1
	If $i = 0 Then ContinueLoop
	If $aArray_mod[$i - 1][0] <> $aArray_mod[$i][0] Then
		_ArraySort($aArray_mod, 0, $k, $i - 1, 1)
		$k = $i
	EndIf
	If $i=UBound($aArray) - 1 Then
		_ArraySort($aArray_mod, 0, $k, $i, 1)
	EndIf
Next

_ArrayDisplay($aArray_mod)
 
A

Alofa

Гость
CreatoR сказал(а):
... Но тут есть проблема...
CreatoR
А если доработать ваш скрипт так:
Код:
#include <Array.au3>

Dim $asArray[20] = ['NewA\B\A.jpg', 'New\A.jpg', 'Other\A.jpg', 'NewA\A.jpg', 'New\B\A.jpg', 'Other\B\B.jpg', _
		'Other\C.jpg', 'New1\C.jpg', 'Other\B\C.jpg', 'WOther\B.jpg', 'Other\X\Z.jpg', 'New\B.jpg', _
		'New2\A\B\C\D\E.jpg', 'New2\A\E.jpg', 'New1\A.jpg', 'NewB\A.jpg', 'NewB\B.jpg', 'NewC\C.jpg', _
		'OtherA\B\C\D\E.jpg', 'OtherA\B\C\D\F.jpg']
_ArraySortEx($asArray)
_ArrayDisplay($asArray)

Func _ArraySortEx(ByRef $aArray)
	Local $iSize = UBound($aArray) - 1
	For $i = 0 To $iSize
		$aRes = StringSplit($asArray[$i], '\')
		$asArray[$i] = $aRes[1] & '|' & $aRes[0] & '|' & $asArray[$i]
	Next
	
	_ArraySort($aArray)

	For $i = 0 To $iSize
		$aArray[$i] = StringRegExpReplace($aArray[$i], '^.+\|', '')
	Next
EndFunc   ;==>_ArraySortEx
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Alofa
Джентльмены удачи сказал(а):
Код:
Dim $aArray[20] = ['NewA\B\A.jpg', 'New\A.jpg', 'Other\A.jpg','NewA\A.jpg', 'New\B\A.jpg', 'Other\B\B.jpg', _
                   'Other\C.jpg', 'New1\C.jpg', 'Other\B\C.jpg', 'WOther\B.jpg', 'Other\X\Z.jpg', 'New\B.jpg', _
                   'New2\A\B\C\D\E.jpg', 'New2\A\E.jpg', 'New1\A.jpg', 'NewB\A.jpg', 'NewB\B.jpg', 'NewC\C.jpg', _
                   'OtherA\B\C\D\E.jpg', 'OtherA\B\C\D\F.jpg']
:blum:


Добавлено:
Сообщение автоматически объединено:

Мой вариант.
Код:
#include <Array.au3>

;~ Dim $aArray[5] = ['Other\A.jpg', 'Other\B\A.jpg', 'Other\B\B.jpg', 'Other\C.jpg', 'Other\B\C.jpg']
;~ Dim $aArray[10] = ['New\A.jpg','Other\A.jpg', 'New\B\A.jpg', 'Other\B\B.jpg', 'Other\C.jpg', 'New\C.jpg', 'Other\B\C.jpg', 'New\B.jpg', 'New\A\B\C.jpg', 'New\A\B\A.jpg']
Dim $aArray[20] = ['NewA\B\A.jpg', 'New\A.jpg', 'Other\A.jpg','NewA\A.jpg', 'New\B\A.jpg', 'Other\B\B.jpg', _
                   'Other\C.jpg', 'New1\C.jpg', 'Other\B\C.jpg', 'WOther\B.jpg', 'Other\X\Z.jpg', 'New\B.jpg', _
                   'New2\A\B\C\D\E.jpg', 'New2\A\E.jpg', 'New1\A.jpg', 'NewB\A.jpg', 'NewB\B.jpg', 'NewC\C.jpg', _
                   'OtherA\B\C\D\E.jpg', 'OtherA\B\C\D\F.jpg']

_ArrayDisplay($aArray, 1)
_BubbleSortEx($aArray)
_ArrayDisplay($aArray, 2)

Func _BubbleSortEx(ByRef $aArray)

	Local $aTmp[UBound($aArray)][2]

	For $i = 0 To UBound($aArray) -1
		$aPath = StringSplit($aArray[$i], "\")
		$aTmp[$i][0] = $aArray[$i]
		For $w  = 1 To UBound($aPath) -1
			$aPath[0] += 1
			$aTmp[$i][1] &= $aPath[$w] & $aPath[0]
		Next
	Next

	$aArray = $aTmp

	For $i = 0 To UBound($aArray) -1
		For $j = ($i+1) To UBound($aArray)-1
			If ($aArray[$j][1] < $aArray[$i][1]) Then
					$sTmp1 = $aArray[$i][0]
					$sTmp2 = $aArray[$i][1]
					$aArray[$i][0] = $aArray[$j][0]
					$aArray[$i][1] = $aArray[$j][1]
					$aArray[$j][0] = $sTmp1
					$aArray[$j][1] = $sTmp2
			EndIf
		Next
	Next

	ReDim $aArray[UBound($aArray)][1]
EndFunc ;==> _BubbleSortEx
 
A

Alofa

Гость
Garrett сказал(а):
Код:
Dim $aArray[20] = ['NewA\B\A.jpg', 'New\A.jpg', 'Other\A.jpg','NewA\A.jpg', 'New\B\A.jpg', 'Other\B\B.jpg', _
                   'Other\C.jpg', 'New1\C.jpg', 'Other\B\C.jpg', 'WOther\B.jpg', 'Other\X\Z.jpg', 'New\B.jpg', _
                   'New2\A\B\C\D\E.jpg', 'New2\A\E.jpg', 'New1\A.jpg', 'NewB\A.jpg', 'NewB\B.jpg', 'NewC\C.jpg', _
                   'OtherA\B\C\D\E.jpg', 'OtherA\B\C\D\F.jpg']
:blum:
Подправил пост :dance1:
Garrett Спасибо.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Супер, всем спасибо.

Возьму на вооружение вариант от Alofa, его не сложно адаптировать под 2D массив.

Только один вопрос, почему _BubbleSortEx?
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
CreatoR [?]
Только один вопрос, почему _BubbleSortEx?
Я её модифицировал, согласно ваших пожеланий, вложив внутрь функцию предварительной подготовки массива, отсюда и название. Впрочем в основе всё тот же метод пузырьковой сортировки.
Название не критично, можно менять как угодно.


Добавлено:
Сообщение автоматически объединено:

Кстати, я бы сделал так.
Код:
;...
    For $i = 0 To $iSize
;~         $aArray[$i] = StringRegExpReplace($aArray[$i], '^.+\|', '')
        $aArray[$i] = StringSplit($asArray[$i], '|', 2)[2]
    Next
;...
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Сделал адаптацию под двумерный массив:

Код:
Func _ArraySortByFilePath(ByRef $aArray, $iDescending = 0, $iStart = 0, $iEnd = 0, $iSubItem = 0, $iPivot = 0)
    If Not IsArray($aArray) Then Return SetError(1, 0, 0)
	
	Local $iUBound = UBound($aArray) - 1
	If $iUBound = -1 Then Return SetError(2, 0, 0)
	
	If $iEnd = Default Then $iEnd = 0
	If $iEnd < 1 Or $iEnd > $iUBound Then $iEnd = $iUBound
	If $iStart < 0 Or $iStart = Default Then $iStart = 0
	If $iStart > $iEnd Then Return SetError(3, 0, 0)
	If $iSubItem < 0 Or $iSubItem > UBound($aArray, 0) - 1 Or $iSubItem = Default Then $iSubItem = 0
	
	Local $aRes
	
	Switch UBound($aArray, 0)
		Case 1
			For $i = $iStart To $iEnd
				$aRes = StringSplit($aArray[$i], '\')
				$aArray[$i] = $aRes[1] & '|' & $aRes[0] & '|' & $aArray[$i]
			Next
			
			_ArraySort($aArray, $iDescending, $iStart, $iEnd, $iSubItem, $iPivot)

			For $i = $iStart To $iEnd
				$aArray[$i] = StringSplit($aArray[$i], '|', 2)[2]
			Next
		Case 2
			For $i = $iStart To $iEnd
				$aRes = StringSplit($aArray[$i][$iSubItem], '\')
				$aArray[$i][$iSubItem]= $aRes[1] & '|' & $aRes[0] & '|' & $aArray[$i][$iSubItem]
			Next
			
			_ArraySort($aArray, $iDescending, $iStart, $iEnd, $iSubItem, $iPivot)

			For $i = $iStart To $iEnd
				$aArray[$i][$iSubItem] = StringSplit($aArray[$i][$iSubItem], '|', 2)[2]
			Next
		Case Else
			Return SetError(4, 0, 0)
	EndSwitch
	
    Return 1
EndFunc
 
A

Alofa

Гость
CreatoR
Тут вот обнаружились проблемы.
В некоторых случаях сортировка не будет произведена корректно:
[list type=decimal][*]Если уровень вложенности больше 10;
[*]Если в конце строки стоит знак "\";
[*]Если корневое название оканчивается на двух (или более) значную цифру, при условии что остальные названия могут содержать менее значную цифру.[/list]
Код:
Dim $asArray[7] = ['XOtherA\Bkk\A.jpg', 'Othe20rh\A\B.jpg\', 'Othe5rh\B\A.jpg', 'Other-20\B.jpg', 'Other-5\C.jpg', 'Other\D\G\Z\.jpg', 'Other\D\G\Z\J\K\U\R\H\N\B\A.jpg']


Первые два пункта я-то додумался, как победить:
Код:
#include <Array.au3>

Dim $asArray[7] = ['XOtherA\Bkk\A.jpg', 'Othe20rh\A\B.jpg\', 'Othe5rh\B\A.jpg', 'Other-20\B.jpg', 'Other-5\C.jpg', 'Other\D\G\Z\.jpg', 'Other\D\G\Z\J\K\U\R\H\N\B\A.jpg']

_ArraySortEx($asArray)
_ArrayDisplay($asArray)

Func _ArraySortEx(ByRef $asArray)
	Local $iSize = UBound($asArray) - 1
	For $i = 0 To $iSize
		$aRes = StringRegExp($asArray[$i], '^[^\\]+|(\\[^\\]+)', 3)
		$asArray[$i] = $aRes[0] & '|' & StringFormat('%03s', UBound($aRes)) & '|' & $asArray[$i]
	Next

	_ArraySort($asArray)

	For $i = 0 To $iSize
		$asArray[$i] = StringRegExpReplace($asArray[$i], '^.+\|', '')
	Next
EndFunc   ;==>_ArraySortEx
... а вот с последним "Тут нужно Бумажно подумать".


Добавлено:
Сообщение автоматически объединено:

Это особенность сортировки "_ArraySort()", ни как в проводнике Windows.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Тут есть ещё одна проблема, поважнее думаю будет...

Код:
$sList = _
	'A.JPG' & @CRLF & _
	'IMG_6567.JPG' & @CRLF & _
	'IMG_6571.JPG' & @CRLF & _
	'IMG_6572.JPG' & @CRLF & _
	'B.JPG' & @CRLF & _
	'Other\IMG_6694.JPG' & @CRLF & _
	'Other\IMG_6693.JPG' & @CRLF & _
	'Home\IMG_6523.JPG' & @CRLF & _
	'Home\IMG_6515.JPG'

$aArray = StringRegExp($sList, '[^\r\n]+', 3)

_ArrayDisplay($aArray)
_ArraySortEx($aArray)
_ArrayDisplay($aArray)


пути без \ должны быть все в начале.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Вроде так решается:

Код:
Func _ArraySortEx(ByRef $asArray)
    Local $iSize = UBound($asArray) - 1
	Local $aRes, $iUbnd
	
    For $i = 0 To $iSize
        $aRes = StringRegExp($asArray[$i], '^[^\\]+|(\\[^\\]+)', 3)
		$iUbnd = UBound($aRes)
		$asArray[$i] = ($iUbnd = 1 ? '0' : '') & $aRes[0] & '|' & StringFormat('%03s', $iUbnd) & '|' & $asArray[$i]
    Next
	
    _ArraySort($asArray)
	
    For $i = 0 To $iSize
        $asArray[$i] = StringRegExpReplace($asArray[$i], '^.+\|', '')
    Next
EndFunc
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
CreatoR
Сортировка моего варианта.
Такой порядок соответствует вашей задумке?
A.JPG
B.JPG
IMG_6571.JPG
IMG_6571.JPG
New1\A.jpg
New1\C.jpg
New2\A\E.jpg
New2\A\B\C\D\E.jpg
New\A.jpg
New\B.jpg
New\B\A.jpg
NewA\A.jpg
NewA\B\A.jpg
NewB\A.jpg
NewB\B.jpg
NewC\C.jpg
Othe20rh\A\B.jpg
Othe5rh\B\A.jpg
Other\D\G\Z\J\K\U\R\H\N\B\A.jpg
Other-20\B.jpg
Other-20\B.jpg
Other\A.jpg
Other\C.jpg
Other\B\B.jpg
Other\B\C.jpg
Other\X\Z.jpg
OtherA\B\C\D\E.jpg
WOther\B.jpg
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Garrett [?]
Такой порядок соответствует вашей задумке?
Почти, только мне кажется что короткие имена должны идти раньше длинных (они же как бы меньше по значению)...
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Мой вариант до кучи (чисто в академических целях).
Правило выбора первого значения в алгоритме сортировки мне до конца не понятно, я остановился на _ArraySort
Код:
#include <Array.au3>

Dim $aArray[20] = ['NewA\B\A.jpg', 'New\A.jpg', 'Other\A.jpg','NewA\A.jpg', 'New\B\A.jpg', 'Other\B\B.jpg', _
                   'Other\C.jpg', 'New1\C.jpg', 'Other\B\C.jpg', 'WOther\B.jpg', 'Other\X\Z.jpg', 'New\B.jpg', _
                   'New2\A\B\C\D\E.jpg', 'New2\A\E.jpg', 'New1\A.jpg', 'NewB\A.jpg', 'B.jpg', 'NewC\C.jpg', _
                   'OtherA\B\C\D\E.jpg', 'OtherA\B\C\D\F.jpg']


$textArray = _ArrayToString($aArray, @CRLF)
;MsgBox(0,"",$textArray)
$pattern1 = "(?m)^()[^\\]*?$|^(.*?)\\[^\\]*?$"
$aDIRs = StringRegExp($textArray, $pattern1,3)
$aDIRs = _ArrayUnique($aDIRs, Default, Default, Default, 0)
_sort_DIR($aDIRs)	; получили список всех задействованных каталогов [отсортированный и без повторений]
;_ArrayDisplay($aDIRs)

Local $sRes = ""

For $i = 0 To UBound($aDIRs)-1	; перебираем полученный спс
	$subpattern = StringReplace($aDIRs[$i], "\", "\\")
	If $subpattern == "" Then
		$pattern2 = "(?ms)^([^\\]*?)$"	; если это корневой каталог, то он без слеша
	Else
		$pattern2 = "(?ms)^" & $subpattern & "\\([^\\]*?)$"
	EndIf
	$aFILEs = StringRegExp($textArray, $pattern2,3)	; получаем из исходного списка файлы данного каталога
	For $j=0 To UBound($aFILEs)-1
		If $aDIRs[$i] == "" Then
			$sRes = $sRes & $aFILEs[$j]
		Else
			$sRes = $sRes & $aDIRs[$i] & "\" & $aFILEs[$j]
		EndIf
		If ($i < UBound($aDIRs)-1) Or ($j < UBound($aFILEs)-1) Then $sRes &= @CRLF ; отсекаем самую последнюю строку
	Next
Next

MsgBox(0, "res", $sRes)

Func _sort_DIR(ByRef $aParam1)
	_ArraySort($aParam1)
EndFunc

OffTopic:
И, главное, сам формировал такой список файлов несколько месяцев назад. Почему мне тогда в голову не пришло такой скрипт написать?...
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
C2H5OH
B.jpg
NewC\C.jpg
New\A.jpg
New\B.jpg
New\B\A.jpg
New1\C.jpg
New1\A.jpg
New2\A\E.jpg
New2\A\B\C\D\E.jpg
NewA\A.jpg
NewA\B\A.jpg
NewB\A.jpg

Other\A.jpg
Other\C.jpg
Other\B\B.jpg
Other\B\C.jpg
Other\X\Z.jpg
OtherA\B\C\D\E.jpg
OtherA\B\C\D\F.jpg
WOther\B.jpg
И т.д.
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Garrett

NewC\C.jpg исправил. Да, в первом шаблоне (?s) была лишней.

А чем
NewA\A.jpg
NewA\B\A.jpg
NewB\A.jpg

не понравились?
Если все Other должны идти подряд, то и все NewA должны идти подряд.
 
Верх