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

Ascan ?

Dima: [pre2] Есть массив вида {{},{},{}} поиск веду в первом элементе do while !eof() .. if ascan(klnmas[1],{|fff| fff==nakl_r1->kod_kl})==0 skip loop endif ....... skip enddo медленновато что то или меня уже плющит.... есть какой то другой аналог Ascan который пошустрее работает ? Понятно что вот так быстрее будет if ascan(klnmas[1],nakl_r1->kod_k)==0 skip loop endif RDD скипает быстрее чем работает Ascan с блоком кода.... [/pre2]

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

Pasha: Поиск в ascan выполняется методом полного перебора массива, так что это медленный поиск. С использованием блока кода он будет еще медленнее, но и без блока кода медленно. Особенно в большом массиве. Особенно в цикле. Насчет того, чем заменить: у меня этих ascan'ов хоть пруд пруди. Вкратце их алгоритм: надо при заполнении массива сразу его сортировать, и использовать быстрый поиск в отсортированном массиве. Но точно так же работает хэш, так что может быть стоит использовать вместо моих нестандартных функций стандартные средства харбора для работы с хэш. Если я правильно понял твою задачу, ты формируешь двумерный массив с размерностями 3*n, где в первом подмассиве хранятся ключи, а в двух следующих - соответствующие им данные. Если "перевернуть" массив, т.е. использовать размерности не 3*n, а n*3, то можно будет использовать хэш, примерно как в примере Петра: http://clipper.borda.ru/?1-4-0-00000784-000-0-0-1354477086 только можно вместо _AADD(hDim,{495, 1}) вызывать _AADD(hDim,{495, x1, x2, ...}) т.е. варьировать 2-ю размерность Ну а свою функцию я когда-то давно выкладывал в теме: https://groups.google.com/forum/#!topicsearchin/comp.lang.xharbour/sorted$20array/comp.lang.xharbour/b0jKrNhcNAk в этой же теме Пшемек рассказывает, как использовать хеш

petr707: В этой задаче можно завершать поиск , если хотя бы один элемент найден, как делает ASCAN2() (см. ниже) в отличие от ASCAN(), который все равно проверяет весь массив. Function ascan2(arr,bl, nstart, nqu ) Local n:=0,m,L:=len(arr),nret:=0,nend Local lbl:= ( valtype(bl)="B") if nstart=NIL nstart=1 endif if nqu=NIL nend:=L else nend:=nstart-1+nqu endif for n=nstart to nend if lbl if eval(bl,arr[n]) nret :=n EXIT endif else if bl==arr[n] nret :=n EXIT endif endif//lbl next i return nret

Pasha: petr707 пишет: как делает ASCAN2() (см. ниже) в отличие от ASCAN(), который все равно проверяет весь массив. Неправда. ASCAN работает точно также. Когда искомый элемент найден, цикл сразу же завершается, и возвращается индекс элемента. В этом нетрудно убедиться, посмотрев на сырцы hb_arrayScan вот фрагмент этой функции для поиска строки в массиве: [pre2] else if( HB_IS_STRING( pValue ) ) { do { PHB_ITEM pItem = pBaseArray->pItems + nStart++; /* NOTE: The order of the pItem and pValue parameters passed to hb_itemStrCmp() is significant, please don't change it. [vszakats] */ if( HB_IS_STRING( pItem ) && hb_itemStrCmp( pItem, pValue, fExact ) == 0 ) return nStart; } while( --nCount > 0 ); } [/pre2] Поиск в этой функции реализован самым оптимальным образом. Но это не делает оптимальным сам алгоритм полного перебора.


Dima: Pasha Спасибо за подробный ответ ! Pasha пишет: Если я правильно понял твою задачу, ты формируешь двумерный массив с размерностями 3*n, где в первом подмассиве хранятся ключи, а в двух следующих - соответствующие им данные. Ну не совсем так. Изначально создается массив amas:={{},{},{}} c 3 элементами где каждый элемент массив. Затем я обрабатываю справочник контрагентов на предмет условий заданных юзером и заполняю первый элемент кодами контрагентов. Остальные 2 элемента так же заполняются соответствующими цифирками. После этого я обрабатываю журнал накладных , предварительно установив в нем SCOPE за интервал дат (по индексу типа DTOS(data_n)) и хожу в цикле проверяя массив (отсеивая не нужных контрагентов). Вот и все. Думаю сортировка массива скорости не прибавит так же как и работа с хэш. По любому этот отчет в Harbour cтроится в разы быстрее нежели в Clipper+SIX или Clipper+ADS. Просто хотелось еще не много ускорить ;)

Pasha: Dima пишет: Думаю сортировка массива скорости не прибавит так же как и работа с хэш. Для небольших массивов разница будет несущественной, а для больших - просто огромной. Вот к примеру такой тест: func main Local nSize := 10000, nI, nKey, nSec, nRes Local aDim := {}, aDim2 := {} Local hDim := { => } // заполнение массива и хеша for nI := 1 to nSize nKey := ((nI + Int(nSize/2)) % nSize) + 1 AADD(aDim, nKey) AADD(aDim2, nI) _AADD(hDim, nKey, nI) next nRes := 0 ? 'Array scan', len(aDim) nSec := Seconds() for nI := 1 to nSize nRes += aDim2[ASCAN(aDim, nI)] next ? (Seconds() - nSec)*1000, nRes nRes := 0 ? 'Hash scan', len(aDim) nSec := Seconds() for nI := 1 to nSize nRes += hDim[nI] next ? (Seconds() - nSec)*1000, nRes return nil PROCEDURE _AADD( aHash, nKey, nI ) aHash[nKey] := nI retu Размер nSize я взял 10000, чтобы время хоть как-то отличалось от нуля. Результат выводится в миллисекундах. Для массива у меня получилось 219 мс, для хеша - опять ноль. Если nSize задать 30000, то результат для массива будет 1953 мс, для хеша - 15мс. Разница в производительности выходит на порядки. Это все равно, что сравнивать разницу поиска с помощью skip и seek. Кстати, аналогия получается прямая, поскольку алгоритмы поиска при этом совершенно идентичны.

Dima: Pasha Буду мозговать , спасибо.

nick_mi: Я может не знаю всех дополнительных условий, но для приведенного выше алгоритма почему нельзя сделать индекс <Имя контрагента>+dtos (data) в журнале накладных . Для каждого кантрагента,попадающего под условия, отбираются данные за указанный интервал. В этом случае отпадает перебор по ascan () и отсекаются лишние движения по базе накладных.

Dima: Что то как то не привычны эти Hash и пока что потерялся ;) Как следующий код преобразовать к Hash массивам ? [pre2] ams:={{},{},{}} for i=1 to 100 aadd(ams[1], i ) aadd(ams[2],seconds()) aadd(ams[3],time()) next i:=ascan(ams[1],33) ? ams[1][ i ] ? ams[2][ i ] ? ams[3][ i ] [/pre2] Вот так что ли ..... [pre2] local ams:={=>} local npos for i=1 to 100 ams[ i ]:={seconds(),time()} next if HB_HHASKEY( ams, 33, @nPos ) ? hb_hget(ams,npos)[1] ? hb_hget(ams,npos)[2] endif [/pre2]

SergKis: Dima пишет:Что то как то не привычны эти Hash и пока что потерялся Может поможет: [pre2] oH := bkHash():New() oH:Put('001', aa->Field10) xVal := oH:Get('001', 'NotFound') oH:Sum(cTabNr, zpl->R_16) // DB zarpl. oH:Sum(cTabNr, -(zpl->R_DLT) // DB zarpl. CLASS bkHash VAR oHash _METHOD New() _METHOD Get( xKey, xVal ) _METHOD Put( xKey, xVal ) _METHOD Len() _METHOD Del( xKey ) _METHOD IsKey( xKey ) _METHOD GetI( nElem, lArr ) _METHOD Sum( xKey, xVal ) ENDCLASS METHOD New() CLASS bkHash ::oHash := hb_hash() RETURN Self METHOD Get( xKey, xDef ) CLASS bkHash // IF hb_hHasKey( ::oHash, xKey ); RETURN ::oHash[xKey] // ENDIF RETURN hb_hGetDef( oHash, xKey, xDef) METHOD Put( xKey, xVal ) CLASS bkHash // ::oHash[xKey] := xVal hb_hSet( ::oHash, xKey, xVal ) RETURN .T. METHOD Len() CLASS bkHash RETURN Len(::oHash) METHOD Del( xKey ) CLASS bkHash IF hb_hHasKey( ::oHash, xKey ); hb_hDel(::oHash, xKey) ENDIF RETURN NIL METHOD IsKey( xKey ) CLASS bkHash RETURN hb_hHasKey( ::oHash, xKey ) METHOD GetI( nElem, lArr ) CLASS bkHash IF empty(lArr); RETURN hb_hValueAt(::oHash, nElem) ENDIF RETURN { Hb_hKeyAt(::oHash, nElem), hb_hValueAt(::oHash, nElem) } METHOD Sum( xKey, xVal ) CLASS bkHash LOCAL aSum,i,k,t := valtype(xVal) IF t == "A" k := Len(xVal) aSum := Self:Get( xKey, aFill(array(k), 0) ) IF Len( aSum ) == k AEVal(xVal, {|x,i| aSum[ i ]:= iif(ValType(x)=='N', aSum[ i ]+x, x) } ) ELSE aSum := xVal ENDIF ELSEIF t == "N" aSum := ::Get( xKey, 0 ) IF valtype(aSum) == "N"; aSum += xVal ENDIF ELSE aSum := xVal ENDIF RETURN Self:Put(xKey, aSum) /* Интерфейс --------- hb_Hash( 1,2, ... , 5,6, ....) -> oHash // Много по два hb_hHasKey( oHash, xKey ) -> .T./.F. - наличие ключа hb_hPos( oHash, xKey) -> Позиция ключа hb_hGet( oHash, xKey) -> xValue или ошибка hb_hGetDef( oHash, xKey, xDef) -> если есть то xValue иначе xDef ошибка если oHash не то. hb_hSet( oHash, xKey, xVal) -> oHash добавляет или ставит hb_hDel( oHash, xKey) -> oHash Удаляет hb_hKeyAt( oHash, nPos) -> xKey С Ключ позиции hb_hValueAt( oHash, nPos, xVal) -> Значение с позиции hb_hPairAt( oHash, nPos, [DstKey, DstVal] ) -> { xKey, xVal } Если 3,4 параметры есть то замена иначе вернёт текущее hb_hDelAt( oHash, nPos) -> oHash hb_hKeys( oHash ) -> hb_hValues( oHash ) -> hb_hClear( oHash ) -> oHash hb_hFill( oHash, xVal) -> oHash hb_hClone( oHash ) -> oHash hb_hCopy( oHashSource, oHashDest) -> oHashDest hb_hMerge( oHashDest, oHashSource, bBlock | n ) -> oHashDest Если есть bBlock то на каждом елементе oHashDest выполняется {|xKey, xVal, nPos| ... } hb_hEVal( oHash, bBlock, [nStart], [nCount] ) -> oHash bBlock == {|xKey, xVal, nPos| ...} hb_hScan( oHash, xVal, [nStart],[nCount], [lExact] ) -> nPos | 0 hb_hSort( oHash ) -> oHash // Режимы hb_hCaseMath( oHash, lValue) -> .T. / .F. предыдущий Сравнение с учётом регистра hb_hBinary( oHash, lValue) -> .T. / .F. hb_hAutoAdd( oHash, lValue | nValue ) -> HB_HASH_AUTOADD_ALWAYS HB_HASH_AUTOADD_ASSIGN hb_hKeepOrder( oHash, lValue) -> .T. / .F. hb_hAllocate( oHash, nValue) -> NIL hb_hDefault( oHash, [xValue]) -> xValue получить поставить умалчивоемое Empty( oHash ) -> .T. если размер == 0 Len( oHash ) -> даёт размер Hash hb_IsHash( oHash ) -> .T./.F. hb_IsNul( oHash ) -> если длинна == 0 // ключ в Hash всегда уникальный Ошибки Всегда : oHash не то ( Base 1187 ) nPos не верное ( Base 1123 ) */ [/pre2]

Dima: SergKis Спасибо. Мне вот не понятна одна штука [pre2] aHash := {10=>, 20=>} ? HB_HHASKEY( aHash, 5, @nPos ), nPos // .F. 0 ? HB_HHASKEY( aHash, 10, @nPos ), nPos // .T. 1 ? HB_HHASKEY( aHash, 15, @nPos ), nPos // .F. 1 // почему не ноль ? ? HB_HHASKEY( aHash, 20, @nPos ), nPos // .T. 2 ? HB_HHASKEY( aHash, 25, @nPos ), nPos // .F. 2 // почему не ноль ? [/pre2]

Dima: В общем в первом приближении разобрался. Всем спасибо !

SergKis: SergKis пишет:Может поможет: Небольшой пример вдогонку:[pre2] ... LOCAL a,i,j LOCAL oTotal := bkHash():New() LOCAL oGroup := bkHash():New() LOCAL oTovar := bkHash():New() sele TOVAR INDEX DtoS(DateDok)+VidOper ... ... SetScope(0, DtoS(date())+'30') // документы реализации SetScope(0, DtoS(date())+'30') // за день dbGotop() DO WHILE ! eof() oTotal:Sum('Kol_Sum' , { 1, tovar->SUMMA }) oGroup:Sum(tovar->KodGru , { 1, tovar->KOLVO, tovar->SUMMA }) oTovar:Sum(tovar->KodTovar, { 1, tovar->KOLVO, tovar->SUMMA }) dbSkip(1) ENDDO ... ? ' Отчет о продажах за день :',date() ? '======================================================================' a := oTotal:Get( 'Kol_Sum' ) ? 'Всего: строк -', a[ 1 ], 'сумма -', a[ 2 ] ? '======================================================================' ? 'В том числе по группам:' for i := 1 to len( oGroup ) a := oGroup:GetI( i, .T. ) // return {KodGru,{...}} ? 'группа -', a[ 1 ], 'строк -', a[ 2 ][ 1 ], 'кол-во -', a[ 2 ][ 2 ], 'сумма -', a[ 2 ][ 3 ] next ? '======================================================================' ? 'В том числе по товару:' for i := 1 to len( oTovar ) a := oTovar:GetI( i, .T. ) // return {KodTovar,{...}} ? 'товар -', a[ 1 ], 'строк -', a[ 2 ][ 1 ], 'кол-во -', a[ 2 ][ 2 ], 'сумма -', a[ 2 ][ 3 ] next ? '======================================================================' [/pre2]

Dima: еще тест ;) [pre2] proc main local nfor:=1000000 local i local ms:={} local hms:={=>} local nsec nsec:=seconds() for i=1 to nfor aadd(ms,i) next ? (seconds()-nsec)*1000 //641 nsec:=seconds() for i=1 to nfor hms:=i next ? (seconds()-nsec)*1000 //36937 но если предварительно сделать (до заполнения массива) // hb_hAllocate( hms, nfor ) , тогда время 821 nsec:=seconds() ascan(ms,nfor) ? (seconds()-nsec)*1000 //31 nsec:=seconds() HB_HHASKEY(hms,nfor) ? (seconds()-nsec)*1000 //0 return [/pre2]

Pasha: Конечно, при использовании хеша добавление в него происходит медленнее, чем при добавлении элемента в массив. Это тоже самое, что добавлять записи в файл с индексом медленнее, чем в файл без индекса, так как в первом случае еще обновляется индекс. Выигрыш достигается затем при поиске по ключу. Еще к тому же AADD оптимизирован по выделению памяти, т.е. элементы в него добавляются не по одному. Хеш без такой оптимизации сильно ему проиграет. То, что настолько сильно, для меня сюрприз.

Dima: Есть такая функция aValues := hb_hValues( aHash ) Возвращает массив всех значений массива aHash А нет ли похожей которая возвращает массив значений с определенным ключиком ?

Pasha: Dima пишет: А нет ли похожей которая возвращает массив значений с определенным ключиком ? Так в хеш ключ может быть только в одном экземпляре. И значение может быть одно. Или надо выбрать массив по диапазону ключей ?

Dima: Pasha пишет: Или надо выбрать массив по диапазону ключей ? Да. Я не так выразился.

Pasha: Нет, увы, такой функции нет

Dima: Еще вопросец ;) [pre2] fmas:={} hmas:={=>} dbeval({|| hmas[recno()]:={kod_kl,kmcod,codn}}) fmas:=xxxx() как быстро заполнить массив fmas значениями ключей для kmcod==3 ? BM_DBSETFILTERARRAY(fmas) [/pre2]

Dima: Пока посетила только вот такая идея [pre2] use klient new hb_hAllocate( hmas, lastrec() ) dbeval({|| hmas[recno()]:={kmcod,codgr}}) // для kmcod==3 hb_hEval( hmas, {|key,sval,ind| if(sval[1]==3,aadd(fmas,key),)}) // при размере массива 700000 записей hb_hEval работает 530 мс , хочется что то побыстрее BM_DBSETFILTERARRAY(fmas) dbgotop() browse() [/pre2]

SergKis: Pasha пишет:Конечно, при использовании хеша добавление в него происходит медленнее, чем при добавлении элемента в массив. Это тоже самое, что добавлять записи в файл с индексом медленнее, чем в файл без индекса, так как в первом случае еще обновляется индекс. Выигрыш достигается затем при поиске по ключу. В bcc использовал вашу функцию AADDU(<aArray>, <xKey>, <nSum1>, [nSum2], ...) при переходе на msvc она не перенеслась, стал использовать Hash (class bkHash, sum method. см. выше), протестировал по скорости в bcc оба способа. Ваш на десятые доли секунды быстрее (тестировал одной на годовой базе). Поэтому очень спокойно перешел на Hash.

Dima: Dima пишет: hb_hEval( hmas, {|key,sval,ind| if(sval[1]==3,aadd(fmas,key),)}) // при размере массива 700000 записей hb_hEval работает 530 мс , хочется что то побыстрее [pre2] dbeval( {|| hmas[recno()]:={kod_kl,nomer}}) ? len(hmas) // 700000 ключей fmas:={} nsec:=seconds() hb_hEval( hmas, {|key,sval,ind| if(sval[1]==5,aadd(fmas,key),)}) ? (seconds()-nsec)*1000 // 594 mc fmas:={} nsec:=seconds() for each v in hmas if v:__enumValue()[1]==5 aadd(fmas,v:__enumKey()) endif next ? (seconds()-nsec)*1000 // 437 mc тут побыстрее будет [/pre2] А еще быстрее можно сделать выборку ? ;)

Pasha: Dima пишет: А еще быстрее можно сделать выборку ? ;) Можно перевернуть хеш. То есть, в качестве ключа использовать kmkod, а вместо значения - массив {{recno(), kod_kl, codn}, ...} Если нужны только номера записей, можно добавлять только recno() примерно так: hmas:={=>} // разверну для ясности dbeval go top while ! eof() hmas[kmcod] := {} AADD(hmas[kmcod], {recno(), kod_kl, codn}) // или AADD(hmas[kmcod], recno()) skip enddo Тогда значением hmas[3] будет массив с номерами записей.

Dima: Pasha Да но KMCOD на разных записях может быть одинаковый , поэтому так не годится. Смысл затеи прост. Из заполненного hash массива быстро выбрать нужные Recno() и сложить в массив. Например нужно выбрать всех клиентов у которых код торгового агента KMCOD равен 5 или скажем выбрать всех клиентов у которых код группы CODGR равен 7. Хотелось сделать универсальный хэш массив (для разного рода выборок для фильтра) и такой массив я как бы создал но поиск по нему оставляет желать лучшего по времени. Хотя результат 500 мс для размера массива 700 000 записей тоже не плох. Имея массив с номерами записей BM фильтр ставится в лет. Сейчас такой массив записей я заполняю иначе (юзаю нужный ордер и заполняю массив). Думалось что с хэш массивом будет быстрее так как не надо лишний раз дергать базу.

Pasha: Dima пишет: Да но KMCOD на разных записях может быть одинаковый , поэтому так не годится. Как раз именно так и годится. Значением hmas[kmcod] будет не один номер записи, а массив recno(). И поиск в этом hmas по значению kmkod будет мгновенным. А одним хеш для всех случаев не обойдешься. Если выборки нужны по нескольким параметрам, то надо и делать несколько хеш-массивов, каждый для своего случая. Смысл использования хеш только в мгновенном поиске. Использовать хеш, чтобы затем делать цикл по нему для поиска бессмыссленно.

Pasha: Дима, если работать с хеш непривычно, я могу выложить свои функции для отсортированных массивов. Мне надо только причесать свой код, тот вариант, что я выкладывал раньше, не сохранился. Суть примерно та же, что и хеш, только выглядит несколько нагляднее. К тому же, как выяснилось, при добавлении в хеш по умолчанию не оптимизировано выделение памяти. А у AADD с этим все в порядке.

Dima: Pasha пишет: Смысл использования хеш только в мгновенном поиске. Использовать хеш, чтобы затем делать цикл по нему для поиска бессмыссленно. Это я уже понял и подумаю над твоей идеей. Спасибо Pasha пишет: Если нужны только номера записей, можно добавлять только recno() Да я это понял. Спасибо. Обдумываю.

Dima: Pasha пишет: К тому же, как выяснилось, при добавлении в хеш по умолчанию не оптимизировано выделение памяти я пока делаю так hb_hAllocate( hms, Lastrec() ) и все нормально по скорости добавления. Pasha пишет: Дима, если работать с хеш непривычно, я могу выложить свои функции для отсортированных массивов. Мне надо только причесать свой код, тот вариант, что я выкладывал раньше, не сохранился. Было бы не плохо и это сильно и не горит , хочу еще сам поиграться с хеш массивами.

SergKis: Pasha пишет:тот вариант, что я выкладывал раньше, не сохранился. Это, наверно, они. http://zalil.ru/34366220

Dima: Pasha пишет: тот вариант, что я выкладывал раньше, не сохранился. да он где то есть на форуме я не давно натыкался на эту тему , нужно пошукать немного.

SergKis: Pasha пишет:А одним хеш для всех случаев не обойдешься. Если выборки нужны по нескольким параметрам, то надо и делать несколько хеш-массивов, каждый для своего случая. Как это будет выглядеть применительно к Leto ? "несколько хеш-массивов" надо пополнять или создавать заново ? С предложенным способом от Dima понятно, при загрузке программы создал такой hash и работаю, на клиенте относительно него, пополняя его при LastRec > len(hmas) до потери пульса.

Dima: SergKis пишет: пополняя его при LastRec > len(hmas) до потери пульса И меня та же идея посещала , но LETO пока не юзаю (поигрался малость - ПОНРАВИЛОСЬ) и перевожу прогу с Clipper на Harbour CDX а потом будет и LETO и вопросов будет видимо много. Ты еще не забывай что такой массив еще нужно корректировать и иметь реакцию на удаление записей с учетом что все это может происходить в сети ;) Вообще при таком подходе либо держать нужно кучку hash массивов и юзать BM фильтра или иметь такую же кучку дополнительных индексов (тегов) и юзать SCOPE. И там и там есть свои и плюсы и минусы , в прочем это смотря какая задача и как все там организовано. На вкус и цвет как говорится , товарищей нет SergKis пишет: пополняя его при LastRec > len(hmas) до потери пульса Как славно что не нужно делать вот такой проверки , да и хэш массивов нет в clipper;) [pre2] if len(hmas)<4096 else endif [/pre2]

SergKis: Dima пишет:Вообще при таком подходе либо держать нужно кучку hash массивов Проще работать с dbf MemIO или даже локальным dbf с полями, обеспечивающими быстрый доступ для создания нужных tag-ов и для переключения просмотров browse. С таблицей сервера relation по recno. Для обеспечения секретности можно поля обезличить (типа R_1,R_2,...) или что-то еще. Сейчас через MemIO примерно так делаем, только не весь dbf, а через запросы. Тоже пока без сервера- процесс перевода с Clipper на cdx в разгаре, потом Leto. Dima пишет:Ты еще не забывай что такой массив еще нужно корректировать и иметь реакцию на удаление записей с учетом что все это может происходить в сети ;) В локальном dbf все записи, с учетом удаленных и только ключевые, не изменяемые поля. На сервере можно включит триггер, заполняющий поле типа TimeStamp (или символьное DtoS(Date())+StrTran(Time(), ":", "")+right(hb_ntos(bk_MilliSeconds()), 3)), для запросов по изменениям ...

Pasha: SergKis пишет: Как это будет выглядеть применительно к Leto ? Если использовать Leto, то надо возложить функцию формирования bm-фильтра на сервер. Зачем гонять данные с сервера на клиент, формировать на клиенте массив с номерами записей и затем гнать обратно этот массив на сервер ? Зачем тогда такой сервер нужен ? Сейчас в BMDBF* по set filter массив с номерами записей и так формируется, но это делается без учета scope. Можно исправить этот недостаток. Я вижу 3 пути для этого: 1) Убедить харбор-сообщество сделать это прямо в харборе (пока не получилось). 2) Скопировать сырцы BMDBF* в letodb и внести в них нужные изменения. 3) Сделать в letodb rdd - наследника BMDBF* и переписать в нем метод SetFilter (это сложнее). Ну и наконец, можно на сервере просто добавить функцию, которой вы передавались параметры: имя тэга, scope, filter, и эта функция сама бы формировала bm-фильтр по этим данным

Dima: Pasha Поддерживаю вариант 2 и "можно на сервере просто добавить функцию"

SergKis: Dima пишет:Поддерживаю вариант 2 и "можно на сервере просто добавить функцию" Тоже

SergKis: Pasha пишет:Ну и наконец, можно на сервере просто добавить функцию, которой вы передавались параметры: имя тэга, scope, filter, и эта функция сама бы формировала bm-фильтр по этим данным Можно было бы обойтись этим, но тогда If rddname() == 'LETO' leto_setBmFilter(Tag,Scopr,Filter) Else dbSetFilter(...) Endif тоже как то ...

Pasha: Добавил на сервере letodb функцию LBM_DbSetFilter Вызов функции с клиента: leto_ParseRec( leto_Udf('LBM_DbSetFilter', <xScope>, <xScopeBottom>, <xOrder>, <cFilter>, <lDeleted> ) ) Функция устанавливает bitmap-фильтр по условиям scope, filter, и возвращает буфер с первой записью, удовлетворяющей условию фильтра

Dima: Pasha пишет: LBM_DbSetFilter проясни плиз. если активным является ордер 2 , но в LBM_DbSetFilter я указал xOrder равным 5 , какой ордер будет активным после установки LBM_DbSetFilter ? Должен быть 2 , что то не увидел я в сырцах возврата на прежний индекс после установки LBM_DbSetFilter. Сейчас я ставлю простой фильтр когда SCOPETOP и SCOPEBOTTOM равны вот так. Прежний ордер остается на месте в любом случае после выполнения XbmFilter. [pre2] func XbmFilter(nseaord,xsea,myblock) local ret:=.t. local old_ord:=indexord() local old_rec:=recno() local afilt:={} default myblock to nil dbclearfilter() dbsetorder(nseaord) if dbseek(xsea) dbOrderInfo(DBOI_SCOPEBOTTOM,,, xsea) dbeval({|| aadd(afilt,recno())},myblock,,,,.t.) dbOrderInfo(DBOI_SCOPEBOTTOMCLEAR) endif dbsetorder(old_ord) if len(afilt)>0 BM_DBSETFILTERARRAY(afilt) go top else ret:=.f. dbgoto(old_rec) endif return ret [/pre2]

Pasha: На сервере нет информации о том, какой управляющий индекс у клиента. Поэтому в каждой команде, которая поступает с клиента (для которой это конечно необходимо), должен быть прямо указан индекс. Следовательно, серверу нет необходимости возвращать прежний индекс. Поэтому не должно быть такой ситуации, когда управляющий индекс на клиенте один, а LBM_DbSetFilter получает другой. Чтобы избежать этого, я на клиенте добавил функцию, у которой всего 3 параметра: LBM_DbSetFilter( <xScope>, <xScopeBottom>, <cFilter> ) При этом серверу автоматически передается текущий индекс.

Dima: Pasha пишет: Чтобы избежать этого, я на клиенте добавил функцию, у которой всего 3 параметра: а тут их 5 Pasha пишет: <xScope>, <xScopeBottom>, <xOrder>, <cFilter>, <lDeleted>

Pasha: Это в функции на сервере 5 параметров, так как серверу надо знать управляющий индекс клиента и флаг set deleted. А в клиентской функции 3 параметра: 2 для scope и фильтр.

Dima: Pasha Элементы в хэш массиве располагаются в порядке их добавления или там какой то свой принцип ? Изначально думал что в порядке добавления............но вроде оно не так. ЗЫ Разобрался потестив на примерах. Там свой загадочный принцип сортировки.

Dima: Dima пишет: Изначально думал что в порядке добавления............но вроде оно не так что бы было в порядке добавления юзаем hb_hSetOrder(hmas,.t.)



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