Автор | Сообщение |
|
| |
Пост N: 2792
Зарегистрирован: 17.05.05
|
|
Отправлено: 18.03.13 17:35. Заголовок: Ascan ?
Есть массив вида {{},{},{}} поиск веду в первом элементе 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 с блоком кода....
| |
|
Ответов - 44
, стр:
1
2
3
All
[только новые]
|
|
|
| Администратор
|
Пост N: 2764
Зарегистрирован: 23.05.05
|
|
Отправлено: 18.03.13 20:10. Заголовок: Поиск в ascan выполн..
Поиск в 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 в этой же теме Пшемек рассказывает, как использовать хеш
| |
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 18.03.13 21:43. Заголовок: Неполный поиск сокращает время
В этой задаче можно завершать поиск , если хотя бы один элемент найден, как делает 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
| |
|
|
| Администратор
|
Пост N: 2765
Зарегистрирован: 23.05.05
|
|
Отправлено: 18.03.13 21:52. Заголовок: petr707 пишет: как ..
petr707 пишет: цитата: | как делает ASCAN2() (см. ниже) в отличие от ASCAN(), который все равно проверяет весь массив. |
| Неправда. ASCAN работает точно также. Когда искомый элемент найден, цикл сразу же завершается, и возвращается индекс элемента. В этом нетрудно убедиться, посмотрев на сырцы hb_arrayScan вот фрагмент этой функции для поиска строки в массиве: 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 ); } Поиск в этой функции реализован самым оптимальным образом. Но это не делает оптимальным сам алгоритм полного перебора.
| |
|
|
| |
Пост N: 2793
Зарегистрирован: 17.05.05
|
|
Отправлено: 18.03.13 22:01. Заголовок: Pasha Спасибо за по..
Pasha Спасибо за подробный ответ ! Pasha пишет: цитата: | Если я правильно понял твою задачу, ты формируешь двумерный массив с размерностями 3*n, где в первом подмассиве хранятся ключи, а в двух следующих - соответствующие им данные. |
| Ну не совсем так. Изначально создается массив amas:={{},{},{}} c 3 элементами где каждый элемент массив. Затем я обрабатываю справочник контрагентов на предмет условий заданных юзером и заполняю первый элемент кодами контрагентов. Остальные 2 элемента так же заполняются соответствующими цифирками. После этого я обрабатываю журнал накладных , предварительно установив в нем SCOPE за интервал дат (по индексу типа DTOS(data_n)) и хожу в цикле проверяя массив (отсеивая не нужных контрагентов). Вот и все. Думаю сортировка массива скорости не прибавит так же как и работа с хэш. По любому этот отчет в Harbour cтроится в разы быстрее нежели в Clipper+SIX или Clipper+ADS. Просто хотелось еще не много ускорить ;)
| |
|
|
| Администратор
|
Пост N: 2766
Зарегистрирован: 23.05.05
|
|
Отправлено: 18.03.13 22:36. Заголовок: Dima пишет: Думаю с..
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. Кстати, аналогия получается прямая, поскольку алгоритмы поиска при этом совершенно идентичны.
| |
|
|
| |
Пост N: 2795
Зарегистрирован: 17.05.05
|
|
Отправлено: 18.03.13 23:24. Заголовок: Pasha Буду мозговат..
Pasha Буду мозговать , спасибо.
| |
|
|
| |
Пост N: 89
Зарегистрирован: 19.05.05
|
|
Отправлено: 19.03.13 09:24. Заголовок: Я может не знаю всех..
Я может не знаю всех дополнительных условий, но для приведенного выше алгоритма почему нельзя сделать индекс <Имя контрагента>+dtos (data) в журнале накладных . Для каждого кантрагента,попадающего под условия, отбираются данные за указанный интервал. В этом случае отпадает перебор по ascan () и отсекаются лишние движения по базе накладных.
| |
|
|
| |
Пост N: 2796
Зарегистрирован: 17.05.05
|
|
Отправлено: 19.03.13 10:46. Заголовок: Что то как то не при..
Что то как то не привычны эти Hash и пока что потерялся ;) Как следующий код преобразовать к Hash массивам ? 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 ] Вот так что ли ..... 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
| |
|
|
| постоянный участник
|
Пост N: 166
Зарегистрирован: 17.02.12
|
|
Отправлено: 19.03.13 12:08. Заголовок: Dima пишет:Что то ка..
Dima пишет: цитата: | Что то как то не привычны эти Hash и пока что потерялся |
| Может поможет: Скрытый текст
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 ) */
|
| |
|
|
| |
Пост N: 2797
Зарегистрирован: 17.05.05
|
|
Отправлено: 19.03.13 12:31. Заголовок: SergKis Спасибо. М..
SergKis Спасибо. Мне вот не понятна одна штука 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 // почему не ноль ?
| |
|
|
| |
Пост N: 2798
Зарегистрирован: 17.05.05
|
|
Отправлено: 19.03.13 14:01. Заголовок: В общем в первом при..
В общем в первом приближении разобрался. Всем спасибо !
| |
|
|
|
| постоянный участник
|
Пост N: 167
Зарегистрирован: 17.02.12
|
|
Отправлено: 19.03.13 16:56. Заголовок: SergKis пишет:Может ..
SergKis пишет: Небольшой пример вдогонку: Скрытый текст
... 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 ? '======================================================================'
|
| |
|
|
| |
Пост N: 2812
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.03.13 13:01. Заголовок: еще тест ;) proc m..
еще тест ;) 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
| |
|
|
| Администратор
|
Пост N: 2768
Зарегистрирован: 23.05.05
|
|
Отправлено: 20.03.13 13:27. Заголовок: Конечно, при использ..
Конечно, при использовании хеша добавление в него происходит медленнее, чем при добавлении элемента в массив. Это тоже самое, что добавлять записи в файл с индексом медленнее, чем в файл без индекса, так как в первом случае еще обновляется индекс. Выигрыш достигается затем при поиске по ключу. Еще к тому же AADD оптимизирован по выделению памяти, т.е. элементы в него добавляются не по одному. Хеш без такой оптимизации сильно ему проиграет. То, что настолько сильно, для меня сюрприз.
| |
|
|
| |
Пост N: 2813
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.03.13 13:34. Заголовок: Есть такая функция a..
Есть такая функция aValues := hb_hValues( aHash ) Возвращает массив всех значений массива aHash А нет ли похожей которая возвращает массив значений с определенным ключиком ?
| |
|
|
| Администратор
|
Пост N: 2769
Зарегистрирован: 23.05.05
|
|
Отправлено: 20.03.13 13:54. Заголовок: Dima пишет: А нет л..
Dima пишет: цитата: | А нет ли похожей которая возвращает массив значений с определенным ключиком ? |
| Так в хеш ключ может быть только в одном экземпляре. И значение может быть одно. Или надо выбрать массив по диапазону ключей ?
| |
|
|
| |
Пост N: 2814
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.03.13 13:56. Заголовок: Pasha пишет: Или на..
Pasha пишет: цитата: | Или надо выбрать массив по диапазону ключей ? |
| Да. Я не так выразился.
| |
|
|
| Администратор
|
Пост N: 2770
Зарегистрирован: 23.05.05
|
|
Отправлено: 20.03.13 14:04. Заголовок: Нет, увы, такой функ..
Нет, увы, такой функции нет
| |
|
|
| |
Пост N: 2815
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.03.13 14:07. Заголовок: Еще вопросец ;) fm..
Еще вопросец ;) fmas:={} hmas:={=>} dbeval({|| hmas[recno()]:={kod_kl,kmcod,codn}}) fmas:=xxxx() как быстро заполнить массив fmas значениями ключей для kmcod==3 ? BM_DBSETFILTERARRAY(fmas)
| |
|
|
| |
Пост N: 2816
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.03.13 14:21. Заголовок: Пока посетила только..
Пока посетила только вот такая идея 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()
| |
|
|
| постоянный участник
|
Пост N: 170
Зарегистрирован: 17.02.12
|
|
Отправлено: 20.03.13 14:23. Заголовок: Pasha пишет:Конечно,..
Pasha пишет: цитата: | Конечно, при использовании хеша добавление в него происходит медленнее, чем при добавлении элемента в массив. Это тоже самое, что добавлять записи в файл с индексом медленнее, чем в файл без индекса, так как в первом случае еще обновляется индекс. Выигрыш достигается затем при поиске по ключу. |
| В bcc использовал вашу функцию AADDU(<aArray>, <xKey>, <nSum1>, [nSum2], ...) при переходе на msvc она не перенеслась, стал использовать Hash (class bkHash, sum method. см. выше), протестировал по скорости в bcc оба способа. Ваш на десятые доли секунды быстрее (тестировал одной на годовой базе). Поэтому очень спокойно перешел на Hash.
| |
|
|
|
| |
Пост N: 2817
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.03.13 16:17. Заголовок: Dima пишет: hb_hEva..
Dima пишет: цитата: | hb_hEval( hmas, {|key,sval,ind| if(sval[1]==3,aadd(fmas,key),)}) // при размере массива 700000 записей hb_hEval работает 530 мс , хочется что то побыстрее |
| 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 тут побыстрее будет А еще быстрее можно сделать выборку ? ;)
| |
|
|
| Администратор
|
Пост N: 2771
Зарегистрирован: 23.05.05
|
|
Отправлено: 20.03.13 19:16. Заголовок: Dima пишет: А еще б..
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] будет массив с номерами записей.
| |
|
|
| |
Пост N: 2821
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.03.13 19:29. Заголовок: Pasha Да но KMCOD н..
Pasha Да но KMCOD на разных записях может быть одинаковый , поэтому так не годится. Смысл затеи прост. Из заполненного hash массива быстро выбрать нужные Recno() и сложить в массив. Например нужно выбрать всех клиентов у которых код торгового агента KMCOD равен 5 или скажем выбрать всех клиентов у которых код группы CODGR равен 7. Хотелось сделать универсальный хэш массив (для разного рода выборок для фильтра) и такой массив я как бы создал но поиск по нему оставляет желать лучшего по времени. Хотя результат 500 мс для размера массива 700 000 записей тоже не плох. Имея массив с номерами записей BM фильтр ставится в лет. Сейчас такой массив записей я заполняю иначе (юзаю нужный ордер и заполняю массив). Думалось что с хэш массивом будет быстрее так как не надо лишний раз дергать базу.
| |
|
|
| Администратор
|
Пост N: 2772
Зарегистрирован: 23.05.05
|
|
Отправлено: 20.03.13 19:35. Заголовок: Dima пишет: Да но K..
Dima пишет: цитата: | Да но KMCOD на разных записях может быть одинаковый , поэтому так не годится. |
| Как раз именно так и годится. Значением hmas[kmcod] будет не один номер записи, а массив recno(). И поиск в этом hmas по значению kmkod будет мгновенным. А одним хеш для всех случаев не обойдешься. Если выборки нужны по нескольким параметрам, то надо и делать несколько хеш-массивов, каждый для своего случая. Смысл использования хеш только в мгновенном поиске. Использовать хеш, чтобы затем делать цикл по нему для поиска бессмыссленно.
| |
|
|
| Администратор
|
Пост N: 2773
Зарегистрирован: 23.05.05
|
|
Отправлено: 20.03.13 19:40. Заголовок: Дима, если работать ..
Дима, если работать с хеш непривычно, я могу выложить свои функции для отсортированных массивов. Мне надо только причесать свой код, тот вариант, что я выкладывал раньше, не сохранился. Суть примерно та же, что и хеш, только выглядит несколько нагляднее. К тому же, как выяснилось, при добавлении в хеш по умолчанию не оптимизировано выделение памяти. А у AADD с этим все в порядке.
| |
|
|
| |
Пост N: 2822
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.03.13 19:41. Заголовок: Pasha пишет: Смысл ..
Pasha пишет: цитата: | Смысл использования хеш только в мгновенном поиске. Использовать хеш, чтобы затем делать цикл по нему для поиска бессмыссленно. |
| Это я уже понял и подумаю над твоей идеей. Спасибо Pasha пишет: цитата: | Если нужны только номера записей, можно добавлять только recno() |
| Да я это понял. Спасибо. Обдумываю.
| |
|
|
| |
Пост N: 2823
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.03.13 19:44. Заголовок: Pasha пишет: К тому..
Pasha пишет: цитата: | К тому же, как выяснилось, при добавлении в хеш по умолчанию не оптимизировано выделение памяти |
| я пока делаю так hb_hAllocate( hms, Lastrec() ) и все нормально по скорости добавления. Pasha пишет: цитата: | Дима, если работать с хеш непривычно, я могу выложить свои функции для отсортированных массивов. Мне надо только причесать свой код, тот вариант, что я выкладывал раньше, не сохранился. |
| Было бы не плохо и это сильно и не горит , хочу еще сам поиграться с хеш массивами.
| |
|
|
| постоянный участник
|
Пост N: 173
Зарегистрирован: 17.02.12
|
|
Отправлено: 20.03.13 21:09. Заголовок: Pasha пишет:тот вари..
| |
|
|
| |
Пост N: 2824
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.03.13 21:30. Заголовок: Pasha пишет: тот ва..
Pasha пишет: цитата: | тот вариант, что я выкладывал раньше, не сохранился. |
| да он где то есть на форуме я не давно натыкался на эту тему , нужно пошукать немного.
| |
|
|
| постоянный участник
|
Пост N: 174
Зарегистрирован: 17.02.12
|
|
Отправлено: 20.03.13 21:38. Заголовок: Pasha пишет:А одним ..
Pasha пишет: цитата: | А одним хеш для всех случаев не обойдешься. Если выборки нужны по нескольким параметрам, то надо и делать несколько хеш-массивов, каждый для своего случая. |
| Как это будет выглядеть применительно к Leto ? "несколько хеш-массивов" надо пополнять или создавать заново ? С предложенным способом от Dima понятно, при загрузке программы создал такой hash и работаю, на клиенте относительно него, пополняя его при LastRec > len(hmas) до потери пульса.
| |
|
|
|
| |
Пост N: 2826
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.03.13 22:24. Заголовок: SergKis пишет: попо..
SergKis пишет: цитата: | пополняя его при LastRec > len(hmas) до потери пульса |
| И меня та же идея посещала , но LETO пока не юзаю (поигрался малость - ПОНРАВИЛОСЬ) и перевожу прогу с Clipper на Harbour CDX а потом будет и LETO и вопросов будет видимо много. Ты еще не забывай что такой массив еще нужно корректировать и иметь реакцию на удаление записей с учетом что все это может происходить в сети ;) Вообще при таком подходе либо держать нужно кучку hash массивов и юзать BM фильтра или иметь такую же кучку дополнительных индексов (тегов) и юзать SCOPE. И там и там есть свои и плюсы и минусы , в прочем это смотря какая задача и как все там организовано. На вкус и цвет как говорится , товарищей нет SergKis пишет: цитата: | пополняя его при LastRec > len(hmas) до потери пульса |
| Как славно что не нужно делать вот такой проверки , да и хэш массивов нет в clipper;) if len(hmas)<4096 else endif
| |
|
|
| постоянный участник
|
Пост N: 175
Зарегистрирован: 17.02.12
|
|
Отправлено: 21.03.13 08:20. Заголовок: Dima пишет:Вообще пр..
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)), для запросов по изменениям ...
| |
|
|
| Администратор
|
Пост N: 2775
Зарегистрирован: 23.05.05
|
|
Отправлено: 21.03.13 10:04. Заголовок: SergKis пишет: Как ..
SergKis пишет: цитата: | Как это будет выглядеть применительно к Leto ? |
| Если использовать Leto, то надо возложить функцию формирования bm-фильтра на сервер. Зачем гонять данные с сервера на клиент, формировать на клиенте массив с номерами записей и затем гнать обратно этот массив на сервер ? Зачем тогда такой сервер нужен ? Сейчас в BMDBF* по set filter массив с номерами записей и так формируется, но это делается без учета scope. Можно исправить этот недостаток. Я вижу 3 пути для этого: 1) Убедить харбор-сообщество сделать это прямо в харборе (пока не получилось). 2) Скопировать сырцы BMDBF* в letodb и внести в них нужные изменения. 3) Сделать в letodb rdd - наследника BMDBF* и переписать в нем метод SetFilter (это сложнее). Ну и наконец, можно на сервере просто добавить функцию, которой вы передавались параметры: имя тэга, scope, filter, и эта функция сама бы формировала bm-фильтр по этим данным
| |
|
|
| |
Пост N: 2830
Зарегистрирован: 17.05.05
|
|
Отправлено: 21.03.13 10:18. Заголовок: Pasha Поддерживаю в..
Pasha Поддерживаю вариант 2 и "можно на сервере просто добавить функцию"
| |
|
|
| постоянный участник
|
Пост N: 177
Зарегистрирован: 17.02.12
|
|
Отправлено: 21.03.13 11:08. Заголовок: Dima пишет:Поддержив..
Dima пишет: цитата: | Поддерживаю вариант 2 и "можно на сервере просто добавить функцию" |
| Тоже
| |
|
|
| постоянный участник
|
Пост N: 178
Зарегистрирован: 17.02.12
|
|
Отправлено: 21.03.13 11:34. Заголовок: Pasha пишет:Ну и нак..
Pasha пишет: цитата: | Ну и наконец, можно на сервере просто добавить функцию, которой вы передавались параметры: имя тэга, scope, filter, и эта функция сама бы формировала bm-фильтр по этим данным |
| Можно было бы обойтись этим, но тогда If rddname() == 'LETO' leto_setBmFilter(Tag,Scopr,Filter) Else dbSetFilter(...) Endif тоже как то ...
| |
|
|
| Администратор
|
Пост N: 2778
Зарегистрирован: 23.05.05
|
|
Отправлено: 21.03.13 21:59. Заголовок: Добавил на сервере l..
Добавил на сервере letodb функцию LBM_DbSetFilter Вызов функции с клиента: leto_ParseRec( leto_Udf('LBM_DbSetFilter', <xScope>, <xScopeBottom>, <xOrder>, <cFilter>, <lDeleted> ) ) Функция устанавливает bitmap-фильтр по условиям scope, filter, и возвращает буфер с первой записью, удовлетворяющей условию фильтра
| |
|
|
| |
Пост N: 2858
Зарегистрирован: 17.05.05
|
|
Отправлено: 22.03.13 22:02. Заголовок: Pasha пишет: LBM_D..
Pasha пишет: проясни плиз. если активным является ордер 2 , но в LBM_DbSetFilter я указал xOrder равным 5 , какой ордер будет активным после установки LBM_DbSetFilter ? Должен быть 2 , что то не увидел я в сырцах возврата на прежний индекс после установки LBM_DbSetFilter. Сейчас я ставлю простой фильтр когда SCOPETOP и SCOPEBOTTOM равны вот так. Прежний ордер остается на месте в любом случае после выполнения XbmFilter. 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
| |
|
|
| Администратор
|
Пост N: 2783
Зарегистрирован: 23.05.05
|
|
Отправлено: 23.03.13 01:06. Заголовок: На сервере нет инфор..
На сервере нет информации о том, какой управляющий индекс у клиента. Поэтому в каждой команде, которая поступает с клиента (для которой это конечно необходимо), должен быть прямо указан индекс. Следовательно, серверу нет необходимости возвращать прежний индекс. Поэтому не должно быть такой ситуации, когда управляющий индекс на клиенте один, а LBM_DbSetFilter получает другой. Чтобы избежать этого, я на клиенте добавил функцию, у которой всего 3 параметра: LBM_DbSetFilter( <xScope>, <xScopeBottom>, <cFilter> ) При этом серверу автоматически передается текущий индекс.
| |
|
|
| |
Пост N: 2859
Зарегистрирован: 17.05.05
|
|
Отправлено: 23.03.13 11:26. Заголовок: Pasha пишет: Чтобы ..
Pasha пишет: цитата: | Чтобы избежать этого, я на клиенте добавил функцию, у которой всего 3 параметра: |
| а тут их 5 Pasha пишет: цитата: | <xScope>, <xScopeBottom>, <xOrder>, <cFilter>, <lDeleted> |
|
| |
|
|
|
| Администратор
|
Пост N: 2784
Зарегистрирован: 23.05.05
|
|
Отправлено: 23.03.13 14:08. Заголовок: Это в функции на сер..
Это в функции на сервере 5 параметров, так как серверу надо знать управляющий индекс клиента и флаг set deleted. А в клиентской функции 3 параметра: 2 для scope и фильтр.
| |
|
|
| |
Пост N: 2893
Зарегистрирован: 17.05.05
|
|
Отправлено: 28.03.13 20:07. Заголовок: Pasha Элементы в хэ..
Pasha Элементы в хэш массиве располагаются в порядке их добавления или там какой то свой принцип ? Изначально думал что в порядке добавления............но вроде оно не так. ЗЫ Разобрался потестив на примерах. Там свой загадочный принцип сортировки.
| |
|
|
| |
Пост N: 3617
Зарегистрирован: 17.05.05
|
|
Отправлено: 10.10.13 15:57. Заголовок: Dima пишет: Изначал..
Dima пишет: цитата: | Изначально думал что в порядке добавления............но вроде оно не так |
| что бы было в порядке добавления юзаем hb_hSetOrder(hmas,.t.)
| |
|
Ответов - 44
, стр:
1
2
3
All
[только новые]
|
|
|