Форум » [x]Harbour » [?] asort() в Harbour » Ответить

[?] asort() в Harbour

subbota: asort() в Harbour неправильно работает ( Может кто-то знает где взять правильную ? ) Вот тест: #include "minigui.ch" #include "hbextcdp.ch" Function Main local ar := {} aadd( ar, { 10, "2" } ) aadd( ar, { 1, "1" } ) aadd( ar, { 11, "3" } ) aadd( ar, { 11, "4" } ) asort( ar,,, {|x,y| x[1] <= y[1] } ) //....................Должно быть....Показывает @ 3, 1 say ar[1,2]//...1..............1 @ 4, 2 say ar[2,2]//....2...............3 @ 5, 3 say ar[3,2]//.....3...............2 @ 6, 4 say ar[4,2]//......4...............4 set exact on asize( ar, 0 ) aadd( ar, { "10", "2" } ) aadd( ar, { "1", "1" } ) aadd( ar, { "11", "3" } ) aadd( ar, { "11", "4" } ) asort( ar,,, {|x,y| x[1] <= y[1] } ) //....................Должно быть....Показывает @ 13, 1 say ar[1,2]//...1..............1 @ 14, 2 say ar[2,2]//....2...............3 @ 15, 3 say ar[3,2]//.....3...............2 @ 16, 4 say ar[4,2]//......4...............4 inkey(0) RETURN NIL

Ответов - 36, стр: 1 2 All

Dima: subbota пишет: asort( ar, {|x,y| x[1] <= y[1] } ) asort( ar,,,{|x,y| x[1] < y[1] } )

subbota: Dima пишет: asort( ar,,,{|x,y| x[1] < y[1] } ) Да такое проходит, пробовал с Harbour 3.1 changlog v 16691 но при сравнении по знаку "<" правильй порядок в результате должен быть 1, 2, 4, 3 а не 1, 2, 3, 4 И не дело компенсировать ошибку функции ошибкой в прикладной программе А вот при компиляции с Harbour Version: 3.2.0dev Built on: 2015-05-20 замена "<=" на "<" уже и совсем не поможет Смотрел changlog, ф-ию asort() неоднократно дорабатывали, но по-видимому так и не довели до правильной. Может сообщить разработчикам

SergKis: subbota пишет:но при сравнении по знаку "<" правильй порядок в результате должен быть добавьте '11', '21' ... и опять нарушится символьное сравнение. Если Вы используете свой обработчик, так стройте правильный алгоритм его, например val(x[1]) < val(y[1]) или выравнивайте строки (если это важно) сдвигом вправо до определенной (одинаковой) длины а 3.2 еще в работе, мало ли что поменяют еще


Pasha: asort( ar, {|x,y| x[1] <= y[1] } ) //....................Должно быть....Показывает @ 3, 1 say ar[1,2]//...1..............1 @ 4, 2 say ar[2,2]//....2...............3 @ 5, 3 say ar[3,2]//.....3...............2 @ 6, 4 say ar[4,2]//......4...............4 Здесь просто неверно заданы параметры для asort. 2-й параметр - это номер начального элемента для сортировки. В этом случае он просто игнорируется, и выполняется обычная сортировка массива. Поскольку тип данных элемента - тоже массив, то сортировка не выполняется, и массив остается в первоначальном порядке. В asort вносятся небольшие улучшения, но это именно улучшения, а не исправления каких-то ошибок.

petr707: 1) лучше ar_rez := asort( ar,,,{|x,y| x[1] < y[1] } ) 2) ar[3,1]=ar[4,1]=11 - правило сортировки не выполняется, поэтому в результате - {.. ar[3] , ar[4]..} или {.. ar[4] , ar[3]..} - любой порядок из этих будет правильно выполненным результатом

subbota: Поясняю: Я привел два примера с ошибкой сортировки asort() двумерного массива. В обоих примерах массив сортируется по первому элементу подмассива. В первом примере этот элемент подмамассива числовой, а во втором - символьная строка. Разберу первый пример: local ar := {} aadd( ar, { 10, "2" } ) aadd( ar, { 1, "1" } ) aadd( ar, { 11, "3" } ) aadd( ar, { 11, "4" } ) Если массив правильно отсортировать по первому элементу подмассивов с условием сравнения "<=", то есть так: asort( ar,,, {|x,y| x[1] <= y[1] } ) -то потом при прохождении по массиву ar[] от начала к концу и выводе на экран вторых элементов подмассивов, то есть так: @ 3, 1 say ar[1,2] @ 4, 2 say ar[2,2] @ 5, 3 say ar[3,2] @ 6, 4 say ar[4,2] должны увидеть на экране цифры в порядке: 1, 2, 3, 4 другой порядок, в том числе: 1, 2, 4, 3 - указывает на ошибку сортировки. так как соседние элементы массива ar[] при сортировке должны меняться местами ТОЛЬКО в случае НЕВЫПОЛНЕНИЯ условия ar[ n, 1 ] <= ar[ n+1, 1 ] этому соответствует такой вызов функции: asort( ar,,, {|x,y| x[1] <= y[1] } ) Если же в условии сравнения заменить "<=" на "<" то при правильной работе asort() должны получить порядок вторых элементов: 1, 2, 4, 3 В случае практического применения это означает, что после сортировки массива с равными значениями ключей в двух соседних элементах по условию с "<=" , первым из них должен остаться тот, который и до сортировки был первым. Вот такая ф-ция сортирует правильно, но работает раз в 30 медленнее родной asort() function asort_my( ar, blk ) local i , ie := len( ar ) - 1, flag := .t. local z0 if ie > 1 do while flag flag := .f. for i := 1 to ie if ! eval( blk, ar[ i ], ar[ i+1 ] ) z0 := ar [ i ] ar[ i ] := ar[ i + 1 ] ar[ i + 1 ] := z0 flag := .t. endif next enddo endif return ar

Pasha: subbota пишет: этому соответствует такой вызов функции: asort( ar, {|x,y| x[1] <= y[1] } ) Вот фрагмент из описания функции ASORT: ASORT() Sort an array Syntax ASORT(<aTarget>, [<nStart>], [<nCount>], [<bOrder>]) --> aTarget Arguments <aTarget> is the array to sort. <nStart> is the first element of the sort. If not specified, the default starting position is one. <nCount> is the number of elements to sort. If not specified, all elements in the array beginning with the starting element are sorted. <bOrder> is an optional code block used to determine sorting order. If not specified, the default order is ascending. Параметр bOrder: {|x,y| x[1] <= y[1] } должен быть не вторым, а четвертым для функции ASORT. Если его указать вторым, то он будет проигнорирован. Т.е. надо указать не asort( ar, {|x,y| x[1] <= y[1] } ) а asort( ar,,, {|x,y| x[1] <= y[1] } )

subbota: Согласен с Pasha насчет местоположения блока кода в вызове asort() Примеры в постах исправил, но суть вопроса об ошибке в asort() осталась

subbota: Pasha пишет: надо указать не asort( ar, {|x,y| x[1] <= y[1] } ) а asort( ar,,, {|x,y| x[1] <= y[1] } ) Согласен с Pasha насчет местоположения блока кода в вызове asort() Примеры в постах исправил, но суть вопроса об ошибке в asort() осталась

petr707: Цитата ..так как соседние элементы массива ar[] при сортировке должны меняться местами А из чего такой вывод ? Должны - быть выстроены в итоге по правилу блока кода, но меняться местами - не обязательно, разве нет ? Похоже, что Вам требуется сортировка, где сравнения двух соседних значений недостаточно для определения порядка сортировки ? Например, номер элемента в первичном массиве.

Pasha: Если значения элементов одинаково, то результат выполнения a1[1] <= a2[1] будет равен .t. также a2[1] <= a1[1] тоже .t. В этом случае результат сортировки непредсказуем, он зависит, в каком порядке выполнялось сравнение элементов, так как сам блок кода не содержит точной информации о сравнении элементов. Можно предложить такую функцию для сортировки массива по одному или двум индексам: Function ASortA(a, n, n2) // ------------------------------------------------------------- // Сортирует двухмерный массив по индексу n // Если задан n2 - сортировка по двум индексам // ------------------------------------------------------------- Return ASort(a,,, if(n2 == nil,; {|x1, x2| x1[n] < x2[n]},; {|x1, x2| if(x1[n]=x2[n], x1[n2]<x2[n2], x1[n]<x2[n])} )) для сортировки в вашем случае надо вызвать: ASORTA(aArray, 1, 2) но опять таки, сортировка будет выполняться не по исходному порядку, а по значению 2-го подэлемента

subbota: Pasha пишет: В этом случае результат сортировки непредсказуем Не соглашусь с этим замечанием. В случае когда ключевые значения одинаковы элементы не должны меняться местами. Вот еще готовый пример. Из него видно, что из asort(), index on и sort on правильно работает только index on ( а при правильной работе все они должны давать одинаковый результат ) Пример: private dim := {} * По первому элементу подмассива будет сортировка или индексирование * Во втором элементе подмассива записан * правильный порядковый номер после сортировки или индексирования aadd( dim, { 11, "2" } ) aadd( dim, { 1, "1" } ) aadd( dim, { 12, "3" } ) aadd( dim, { 12, "4" } ) private struct := {} aadd( struct, { "p1", "N", 2, 0 } ) aadd( struct, { "p2", "C", 2, 0 } ) dbcreate( "arr", struct ) use arr.dbf private i for i := 1 to len( dim ) dbappend( ) arr->p1 := dim[i,1] arr->p2 := dim[i,2] next sort on p1 to arsrt.dbf index on p1 to arr asort( dim,,, { |z1,z2| z1[1] <= z2[1] } ) use arsrt new private b1 := "", b2 := "", b3 := "" for i := 1 to len( dim ) b1 += dim[i,2] + " " b2 += arr->p2 b3 += arsrt->p2 arr->( dbskip() ) arsrt->( dbskip() ) next close arr close arsrt clear screen @ 1,0 say " После asort() получен порядок: " + b1 // 1 2 4 3 @ 3,0 say " После index on получен порядок: " + b2 // 1 2 3 4 - правильно @ 5,0 say " После sort on получен порядок: " + b3 // 1 2 4 3 inkey(0)

petr707: Цитата..они должны ..не должны ..правильно По формальной логике, такие утверждения должны быть аргументированы, то есть должны ссылаться на какое-либо правило. В Вашем тексте таких ссылок не обнаружено.

Pasha: subbota пишет: Но asort() ошибается еще более грубо. ... asort( dim, { |z1,z2| z1[1] <= z2[1] } ) Как можно что-то говорить о работе asort, если опять передать этой функции неправильный параметр ? Насчет остального: результат сортировки полностью определяется условием сортировки. В условии сортировки нет никакого первичного номера элемента. Следовательно, все три режима работают правильно (если, конечно, для asort наконец-то указать правильный параметр). Различия в результате объясняются неопределенностью условия сортировки, поскольку алгоритмы сортировки не являются полностью идентичными.

subbota: Проверил то же самое в Clipper 5.2e результат такой После asort() получен порядок: 1 2 4 3 После index on получен порядок: 1 2 3 4 - правильно После sort on получен порядок: 1 2 3 4 - правильно

subbota: Pasha пишет: Как можно что-то говорить о работе asort, если опять передать этой функции неправильный параметр ? Извиняюсь по поводу повторной ошибки в месте параметра условия сортировки. Опять исправил свой пост. Понимаю объяснение насчет неидентичности алгоритмов, но не соглашаюсь с тем что без явного указания в условии сортировки первоначального положения элемента, элементы, имеющие одинаковое значение ключа, в результирующем массиве будут занимать места относительно друг-друга отличающиеся от первоначальных. Это все-таки существенная недоработка asort() и если разработчики ее устранят, то в Harbour будет одним подводным камнем меньше. То же и про sort on. Замена index on на sort on и на asort() не должна провоцировать получения неидентичных резудьтатов. *---- Я об этот подводный камень споткнулся впервые давно на Clipper. Но тогда не докопался до сути. Думаю, что об него споткнуться еще многие.

petr707: Можно не искать нужный сложный алгоритм.. Просто измените входные данные так, чтобы в принципе не было совпадающих значений при сортировке, например сортируйте не по 1 элементу массива, а по 3-му - он только для сортировки, и его значение, к примеру ar[n,3] := str(ar[n,1),10] +str(n,5) При равенстве значений ar[n,1] - будет учтен порядковый номер в массиве.

Dima: local ar := {} cls aadd( ar, { 10, "2" } ) aadd( ar, { 1, "1" } ) aadd( ar, { 11, "3" } ) aadd( ar, { 11, "4" } ) asort( ar,,, {|x,y| x[1] <= y[1] } ) @ 3, 1 say ar[1,2]//...1..............1 @ 4, 2 say ar[2,2]//....2...............3 @ 5, 3 say ar[3,2]//.....3...............2 @ 6, 4 say ar[4,2]//......4...............4 wait Clipper 5.2e Результат 1 2 4 3

SergKis: все правильно, не до конца продуман обработчик для asort и для {11,'3'}, {11,'4'} перестановки не являются нарушением условия и претензий к asort не принимаются, мое мнение. Пишите правильный обработчик.

Dima: SergKis пишет: Пишите правильный обработчик. +1



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