Форум » [x]Harbour » сортировка двухмерного массива » Ответить

сортировка двухмерного массива

finder: Доброе время суток Прошу помощи если у кого есть возможность и желание, у меня крыша уже начинает съезжать ( Есть двухмерный массив, в котором array[N,1] - путь, array[N,2] - позиция на своем уровне вложения в пути, array[N,3] - уровень вложения. {{'/a', 1, 0 },{'/b', 3, 0 },{'/c', 2, 0 },{'/a/a', 2, 1 },{'/a/b', 1, 1 },{'/b/a', 1, 1 },{'/b/b', 2, 1 },{'/c/a', 2, 1 },{'/c/b', 1, 1 },{'/a/a/a', 3, 2 },{'/a/a/b', 2, 2 },{'/a/a/c', 1, 2 },{'/b/a/a', 1, 2 },{'/c/a/a', 1, 2 },{'/b/a/a/a/', 1, 3 }} Требуется отсортировать согласно указанных позиций на каждом уровне/подуровне вложения с правильной выходной структурой. Хотелось бы получить такой результат: {'/a', 1, 0 } {'/a/b', 1, 1 } {'/a/a', 2, 1 } {'/a/a/c', 1, 2 } {'/a/a/b', 2, 2 } {'/a/a/a', 3, 2 } {'/c', 2, 0 } {'/c/b', 1, 1 } {'/c/a', 2, 1 } {'/c/a/a', 1, 2 } {'/b', 3, 0 } {'/b/a', 1, 1 } {'/b/a/a', 1, 2 } {'/b/a/a/a/', 1, 3 } {'/b/b', 2, 1 } Сортировки asort()-ом с разными условиями и попытки описать свой сортировщик довели почти до истерики. Смысл в том что позиция и алфавитная сортировка создают противоречия в условиях и не получается отсортировать именно как требуется. HELP P.S. Свои варианты сортировки не указывал, но все строилось на 2 базовых вариантах: asort( aTest,,, {|a,b| left( a[1], rat( '/', a[1] ) ) + str( a[2], 2 ) < left( b[1], rat( '/', b[1] ) ) + str( b[2], 2 ) } ) - сортирует уровень+порядок и asort( aFullList,,, {|a,b| a[1] + '/' < b[1] + '/' } ) - сортирует по алфавиту согласно структуре оба варианта пытался обвязать расширенными условиями в кодоблоке и нефига ( отсортировать в нужном порядке с сохранением структу не вышло

Ответов - 5

petr707: Записываете массив в таблицу с тремя полями ar1 ar2 ar3 потом индекс - что-то типа f(ar1)+str(ar2,2)+str(ar3,2) , где f - Ваша нужная функция ну и отсортированную таблицу по индексу - обратно в массив

Pasha: КМК, задача неразрешима средствами ASORT. Если я правильно понял саму задачу. Возьмем 2 элемента: {'/c/b', 1, 1 } и {'/b/a', 1, 1 } почему 1-й элемент меньше 2-го ? Потому, что {'/c', 2, 0 } < {'/b', 3, 0 } То есть, для сравнения первых 2-х элементов недостаточно информации, в них содержащейся. Нужно еще брать информацию из элементов предыдущего уровня. А ASORT ее не даст.

Sergy: finder пишет: Хотелось бы получить такой результат: {'/a', 1, 0 } {'/a/b', 1, 1 } {'/a/a', 2, 1 } {'/a/a/c', 1, 2 } {'/a/a/b', 2, 2 } {'/a/a/a', 3, 2 } Прямое противоречие: сначала а потом ab потом aa или: сначала aa потом aac потом aab потом aaa Это уже и не сортировка, а перестановка согласно неких внутренних условий. Я-бы сделал функцию, которая возвращает "вес" трех элементов массива {строка, число, число}. Например: FUNC MyFunc(aDim) LOCAL cResult cResult := PADR(CHARREM("\",aDim[1]),3) // строка вида "a ", "aab", "abb" и тп cResult += STR(aDim[2]) cResult += STR(aDim[3]) RETURN cResult Далее ASORT(aTest,,,{|a,b| MyFunc(a) < MyFunc(b)}) Если я не очень правильно уловил суть задачи - внутри MyFunc() легко все поправить. На выходе она должна давать четкий ответ, куда переставлять элементы массива.


PSP: КМК ( (c) Pasha :) ), можно сначала привести массив к древовидному, отсортировав каждую ветку как нужно (ведь тогда останется только одно условие для каждой ветки), а потом рекурсией собрать опять в двумерный.

finder: Спасибо. Вы все подтвердили что простого решения нет, а то я уже переживать начал что мозги застыли. В общем на данный момент остановился на таком варианте: Procedure Main local aRow := {}, aRez := {} local aIn := { {'/a', 1, 0 }, {'/b', 3, 0 }, {'/c', 2, 0 }, {'/a/a', 2, 1 }, {'/a/b', 1, 1 }, {'/b/a', 1, 1 }, {'/b/b', 2, 1 }, ; {'/c/a', 2, 1 }, {'/c/b', 1, 1 }, {'/a/a/a', 3, 2 }, {'/a/a/b', 2, 2 }, {'/a/a/c', 1, 2 }, {'/b/a/a', 1, 2 }, ; {'/c/a/a', 1, 2 }, {'/b/a/a/a/', 1, 3 } } asort( aIn,,, {|a,b| left( a[1], rat( '/', a[1] ) ) + str( a[2], 2 ) < left( b[1], rat( '/', b[1] ) ) + str( b[2], 2 ) } ) sorter( @aIn, @aRez, '/', 0 ) ? FOR EACH aRow IN aRez ? hb_valtoexp(aRow) NEXT ? Return Function sorter( aSrc, aDst, cMask, nLevel ) local nFor := 0 for nFor=1 to len( aSrc ) if aSrc[nFor,3] = nLevel .and. left( aSrc[nFor,1], rat( '/', aSrc[nFor,1] ) ) == cMask aadd( aDst, aSrc[nFor] ) sorter( @aSrc, @aDst, aSrc[nFor,1]+'/', aSrc[nFor,3]+1 ) endif next Return .T. не оптимально, но по крайней мере работает верно, хоть и делает лишние действия. Возможно получится еще как-то оптимизировать.



полная версия страницы