Форум » [x]Harbour » Подскажите алгоритм объединения сумм по одинаковому месяцу ? » Ответить

Подскажите алгоритм объединения сумм по одинаковому месяцу ?

Andrey: Всем привет. Имею двухмерный массив примерно такой:  21,33 25.01.2011  21,33 01.03.2011  21,33 15.04.2011  21,33 28.04.2011  21,33 11.05.2011  19,00 11.05.2011  21,33 11.05.2011  21,33 11.05.2011  19,00 11.05.2011  19,00 11.05.2011  19,00 11.05.2011  19,00 11.05.2011  19,00 11.05.2011  19,00 11.05.2011  19,00 11.05.2011  19,00 11.05.2011  284,31 11.05.2011  21,33 11.05.2011  21,33 01.06.2011  21,33 30.06.2011  21,33 30.06.2011  21,33 04.08.2011  21,33 10.08.2011  21,33 22.09.2011  21,33 22.09.2011  21,33 22.09.2011 Подскажите алгоритм как можно объеденить суммы по одинаковому месяцу. Т.е. чтоб получился массив такого вида: 21,33 25.01.2011 - пропуск т.к. 1-месяц 21,33 01.03.2011 - пропуск т.к. 1-месяц 42,66 15.04.2011 - объединили 0,00 28.04.2011 - .... 540,63 11.05.2011 - объединили 0,00 11.05.2011 0,00 11.05.2011 0,00 11.05.2011 0,00 11.05.2011 0,00 11.05.2011 0,00 11.05.2011 0,00 11.05.2011 0,00 11.05.2011 0,00 11.05.2011 0,00 11.05.2011 0,00 11.05.2011 0,00 11.05.2011 0,00 11.05.2011 и т.д. Заранее спасибо за ответ...

Ответов - 8

PSP: Как-то так... [pre2] FUNCTION Something( aIn ) LOCAL aElem LOCAL nMon := 0 LOCAL n1st LOCAL aOut := {} // результат FOR EACH aElem IN aIn IF nMon <> Month( aElem[ 2 ] ) nMon := Month( aElem[ 2 ] ) AAdd( aOut, aElem ) n1st := Len( aOut ) ELSE aOut[ n1st, 1 ] += aElem[ 1 ] AAdd( aOut, { 0, aElem[ 2 ] } ) END // IF NEXT RETURN aOut[/pre2]

Dima: Перенес темку сюда.

Andrey: Получилось ! Только не совсем правильно, в первом массиве "затирается" (просуммировался) первый элемент месяца. 1 - 25.01.11 , 21.33 -> 21.33 2 - 01.03.11 , 21.33 -> 21.33 3 - 15.04.11 , 42.66 -> 42.66 4 - 28.04.11 , 21.33 -> 0 5 - 11.05.11 , 540.63 -> 540.63 6 - 11.05.11 , 19.00 -> 0 7 - 11.05.11 , 21.33 -> 0 8 - 11.05.11 , 21.33 -> 0 9 - 11.05.11 , 19.00 -> 0 10 - 11.05.11 , 19.00 -> 0 11 - 11.05.11 , 19.00 -> 0 12 - 11.05.11 , 19.00 -> 0 13 - 11.05.11 , 19.00 -> 0 14 - 11.05.11 , 19.00 -> 0 15 - 11.05.11 , 19.00 -> 0 16 - 11.05.11 , 19.00 -> 0 17 - 11.05.11 , 284.31 -> 0 18 - 11.05.11 , 21.33 -> 0 19 - 01.06.11 , 63.99 -> 63.99 20 - 30.06.11 , 21.33 -> 0 21 - 30.06.11 , 21.33 -> 0 22 - 04.08.11 , 42.66 -> 42.66 23 - 10.08.11 , 21.33 -> 0 24 - 22.09.11 , 63.99 -> 63.99 25 - 22.09.11 , 21.33 -> 0 26 - 22.09.11 , 21.33 -> 0 Вот код: FUNCTION MAIN() LOCAL aDim := {}, nI, aDimOut SET DATE GERMAN SET EPOCH TO 1905 AAdd( aDim, { 21.33 , CTOD("25.01.2011") } ) AAdd( aDim, { 21.33 , CTOD("01.03.2011") } ) AAdd( aDim, { 21.33 , CTOD("15.04.2011") } ) AAdd( aDim, { 21.33 , CTOD("28.04.2011") } ) AAdd( aDim, { 21.33 , CTOD("11.05.2011") } ) AAdd( aDim, { 19.00 , CTOD("11.05.2011") } ) AAdd( aDim, { 21.33 , CTOD("11.05.2011") } ) AAdd( aDim, { 21.33 , CTOD("11.05.2011") } ) AAdd( aDim, { 19.00 , CTOD("11.05.2011") } ) AAdd( aDim, { 19.00 , CTOD("11.05.2011") } ) AAdd( aDim, { 19.00 , CTOD("11.05.2011") } ) AAdd( aDim, { 19.00 , CTOD("11.05.2011") } ) AAdd( aDim, { 19.00 , CTOD("11.05.2011") } ) AAdd( aDim, { 19.00 , CTOD("11.05.2011") } ) AAdd( aDim, { 19.00 , CTOD("11.05.2011") } ) AAdd( aDim, { 19.00 , CTOD("11.05.2011") } ) AAdd( aDim, {284.31 , CTOD("11.05.2011") } ) AAdd( aDim, { 21.33 , CTOD("11.05.2011") } ) AAdd( aDim, { 21.33 , CTOD("01.06.2011") } ) AAdd( aDim, { 21.33 , CTOD("30.06.2011") } ) AAdd( aDim, { 21.33 , CTOD("30.06.2011") } ) AAdd( aDim, { 21.33 , CTOD("04.08.2011") } ) AAdd( aDim, { 21.33 , CTOD("10.08.2011") } ) AAdd( aDim, { 21.33 , CTOD("22.09.2011") } ) AAdd( aDim, { 21.33 , CTOD("22.09.2011") } ) AAdd( aDim, { 21.33 , CTOD("22.09.2011") } ) aDimOut := Something( aDim ) FOR nI := 1 TO Len( aDim ) ? nI, " - ", DTOC(aDim[ nI,2 ]), ", ", aDim[ nI,1 ] , " -> ", aDimOut[ nI,1 ] NEXT wait RETURN NIL //////////////////////////////////////////////////////////// FUNCTION Something( aIn ) LOCAL aElem LOCAL nMon := 0 LOCAL n1st LOCAL aOut := {} // результат FOR EACH aElem IN aIn IF nMon <> Month( aElem[ 2 ] ) nMon := Month( aElem[ 2 ] ) AAdd( aOut, aElem ) n1st := Len( aOut ) ELSE aOut[ n1st, 1 ] += aElem[ 1 ] AAdd( aOut, { 0, aElem[ 2 ] } ) END // IF NEXT RETURN aOut


PSP: Andrey пишет: в первом массиве "затирается" (просуммировался) первый элемент месяца Замени строку AAdd( aOut, aElem ) на AAdd( aOut, AClone( aElem ) )

Andrey: Спасибо БОЛЬШОЕ PSP !!! А то после недельной работы по ночам голова совсем "не варит"...

Pasha: Маленький совет. Насколько я понимаю, исходный массив получен в результате выборки из БД. Результирующий массив можно получить непосредственно, не формируя промежуточный. Примерно так: aRes := {} seek ... while ... AADDQ(aRes, Date, Summa) skip enddo ... func AADDQ(aRes, xKey, nSum) ... retu nil

Pasha: Перенес функцию, формирующую результирующий массив, на C-уровень http://zalil.ru/32298640 Пример использования: Local aRes := {} dbEval({|| AADDU(aRes, Date, Summa)}) 2-й параметр - ключ для поиска в массиве, 3-й и так далее - числовые параметры для суммирования Синтаксис вызова функции: AADDU(<aArray>, <xKey>, <nSum1>, [nSum2], ...) Функция выполняет поиск ключа в массиве методом половинного деления, и работает очень быстро. Результирующий массив получается вида: {{xKey1, nSum1, ...}, {xKey2, nSum2, ...}, ...} Результирующий массив сразу отсортирован В модуле также имеется функция AADDS() с аналогичными параметрами. Ее отличие от AADDU в том, что входной поток для нее предполагается отсортированным, и ключ сравнивается только с последним элементом массива. Но, поскольку метод половинного деления у меня реализован не классическим способом, а несколько модифицированным: сначала сравнение выполняется на границы массива, первый и последний элемент, разница в производительности между AADDU и AADDS незначительна. Вместо поиска в массиве методом половинного деления, конечно, можно с тем же результатом использовать тип данных хэш. Но я уже привык к своему способу, да и, как я уже написал, поиск у меня немного отличается. Тесты показывают, что перенос этого кода на C-уровень дает увеличение производительности примерно в полтора раза. Это при том, что источник данных один и то же. Я сравнивал с функцией, которая в качестве параметра получает подмассив: AADDQ(aRes, {xKey, nSum}) Ну а в сравнении с алгоритмом, используюшим обычный линейный поиск, производительность возрастает раза в 3. В этом модуле есть еще несколько функций работы с массивами, но они уже предназначены для других целей.

Andrey: Pasha пишет: Тесты показывают, что перенос этого кода на C-уровень дает увеличение производительности примерно в полтора раза. Это при том, что источник данных один и то же. Я сравнивал с функцией, которая в качестве параметра получает подмассив: AADDQ(aRes, {xKey, nSum}) Ну а в сравнении с алгоритмом, используюшим обычный линейный поиск, производительность возрастает раза в 3. Ну что сказать - видно руку профессионала ! Спасибо БОЛЬШОЕ !!!



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