OberonCore https://forum.oberoncore.ru/ |
|
Еще один этюд: пошаговый обход многомерного массива https://forum.oberoncore.ru/viewtopic.php?f=27&t=2981 |
Страница 1 из 2 |
Автор: | Peter Almazov [ Вторник, 09 Ноябрь, 2010 11:07 ] | ||
Заголовок сообщения: | Еще один этюд: пошаговый обход многомерного массива | ||
Случайно натолкнулся на этот кусок – резанул глаз выход из середины цикла for. После прочтения комментария, понял, что задача хорошо подходит в качестве этюда при обучении – простая, но нужно подумать. Речь идет о пошаговом обходе многомерного массива. Программа выполняет один шаг – увеличивает текущую комбинацию индексов, начиная с последнего. Если отобразить этот массив на одномерный, то все, что нужно - увеличить его индекс на 1, пока не зайдем за верхнюю границу, тогда _complete = true. Если потом обратно пересчитать одномерный индекс в комбинацию многомерных, то получим ответ. Границы размерностей задаются функциями array.GetUpperBound(номер размерности)и GetLowerBound, последняя не обязательно равна нулю. Но это не принципиально. Вот как решили это в Microsoft (C#). Код: private void IncArray() { Предлагаю дать свои решения. Главное, конечно, описать ход решения или инструмент. Кстати, подозреваю, что решение красиво выглядит на ФЯ, было бы интересно его посмотреть.// This method advances us to the next valid array index, // handling all the multiple dimension & bounds correctly. // Think of it like an odometer in your car - we start with // the last digit, increment it, and check for rollover. If // it rolls over, we set all digits to the right and including // the current to the appropriate lower bound. Do these overflow // checks for each dimension, and if the most significant digit // has rolled over it's upper bound, we're done. // int rank = array.Rank; _indices[rank - 1]++; for (int dim = rank - 1; dim >= 0; dim--) { if (_indices[dim] > array.GetUpperBound(dim)) { if (dim == 0) { _complete = true; break; } for (int j = dim; j < rank; j++) _indices[j] = array.GetLowerBound(j); _indices[dim - 1]++; } } } Свой вариант прилагаю в запароленном виде.
|
Автор: | Alexey Veselovsky [ Вторник, 09 Ноябрь, 2010 12:16 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
А можно уточнить откуда что берется и что должно быть на выходе? Потому как функция без аргументов и без возвращаемого значения, которая при этом тем не менее откуда-то с потолка берет какие-то массивы, меня как-то смущает. |
Автор: | Александр Ильин [ Вторник, 09 Ноябрь, 2010 13:00 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
А мне глаз резануло, что используется вложенный цикл. |
Автор: | Евгений Темиргалеев [ Вторник, 09 Ноябрь, 2010 13:01 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Схема (пред/пост усл. стёр, выписаны в "пробе"): Код: i := 0; WHILE i < n DO x[i] := GetLowerBound(a, i); INC(i) END; Дописал: схема --- пошагового обхода многомерного массива (а не процедуры IncArray)i := n - 1; WHILE x[n - 1] <= GetUpperBound(a, n - 1) DO (* обработать a[x[0], ...., x[n - 1]] *) INC(x[n - 1]) ELSIF (i >= 0) & (x[i] >= GetUpperBound(a, i)) THEN DEC(i) ELSIF i >= 0 THEN INC(x[i]); REPEAT INC(i); x[i] := GetLowerBound(a, i) UNTIL i = n - 1 END Проба: Код: StdCoder.Decode ..,, ..fy....3Qw7uP5PRPPNR9Rbf9b8R79FTvMf1GomCrlAy2xhX,Cb2x
hXhC6FU1xhiZiVBhihgmRiioedhgrZcZRiXFfaqmSrtuGfa4700zdGrr8rmCLLCJuyKtYcZRiX 7.2.s,6AT.,6.5Qw7uP51QCPuP7PNN9F9vQAy1xB.gdj,UBxhYhAbf9P0G2sIdvPZntgcghghZ cZRC8T0E.Ezu.H.hf12.,U08J99SdfJHPNjvQCJuGKfaqmY6MwdONl1QCh0708T,U..w.2YC., sUGpmWbBxhYhAbndMHT9NY6Mw.sQq2Y6cwB.0.J71w,IYAE.0.4kl5.86.QC18RdfQHfMf9R9v Q7ONb17.,.D,,6.I16.M.,U.IZ.2XkD.1.VQ.6.301cUZT1E.s7E.c46.,.16.c8U.E.076i1U 0Ikmj,6.2A2.I16.M.2.J,U.Yr0.B.1cQ,U0o.AU6B.8k,k.4q.kCk.Sp.E3Ua1,E.0E2PP,2e HJ.3Qw7ONhvETPPPPMR9N9fQbf9b8RO3U.Ay2hgq,.RdJ.0EtD.0E.66,E.0.O.2.fU,23A.6F rO.0pd8...oZHlWuKmOpoK46.X5.ELKIrGKf.2Um10..IU.U.AU.4.0k,2.myzzzzB1AUC.H,u 1Im.k.y,g,6E2U.2A0kzXGJ0GoGLu0LRymLOqr8ruqKLyKlKKtyKrCqr8rmuGtKrLOroKaoxhk BhXpZk3hkxbahbmwaaYixIat2bloYnZiVJiohbk2YeAZBgdDZcJZd33YEJidpi3phphh7phYBh XhgnRbBgV7AdB3eDJeI3Y7phUIbx2YdJalQitRi7phg2YAxhbRbBAVBAVIBfEhcBAV7Yctph,J imBaq2YxgV7AV7AcGJe,BfUwd4hV7AV7.............................EEaIbGpWSoW8p Rqk2qUKBcGhV7AVVJbU2eDBdCZe3JeUYeD3Y2BjiB6sCPM0H6ON76NfC,NEZeI1WloaUwd432s F.RfC,NGR0k4aEc8pbCoWGoe8pW0mXKKuKJs0rm8LVyquuKm0GIaKR0mYu2M8p76H0sCaEVKoX aIbqk2akUCpdKIdGJIaKEaIb0mx0HLuGrqmMqLK0GN0nIin4ak28pWGpe8Jb0Goipoqp4akWuI W0mXKKu.UvgV7g,V0.6HTvR9fQ3uP66.Ud.Uv........NvKHPL...i1..HePVOMHfQ,78hOEZ 86l99,NSp76H0M8rN1HcE.aIrumYuKuWGwamR0mYuKLa2arIin4ak242EzaIruGmyKrKKEyId0 GI0HEmnS0GwaGEOGEWGw0GSqXtBZg2YkAZBAV3V7phEVvgV7g,V0.NuPDPGR9N,lYuIEWLR0mU .T0.UKB6HMOp76.i130ko0GRqHE0nRqk2akfWoYmoW0mo0GS0GaKIbWGwaGEGobqk2ak2morSK LaIrGbsRfdhfdQbBU7pd13ZdBZBAV7gcCtCPM0m2mIrqk2KIb2YAxBsCqk2.U2xheQbBAV7o8q .HMON76JfC,NG.k2WLR0Gcy2I8MEZeI.kX.30kYuaD3iZphvgV7AVi3Yu662Y7phEVcYhPphRZ ZU2hPphRBZvg,S3MGRf971Gobk2aIbcPHtCP.uKc44Ug.a0g6i142Er0GTqHE4HK0GMQbBko00 uqR0mfWoYm2H1XdB,7FT86FvKHHEenSAav2Y7pd13Zd769eH7uCcH9uJFNMN76FnMKnimGEW4d NLN76FXngfg6OIaRZZUUlgfg222aRZZUkQqJK00lNLN76waRZZUEPqJK00fNLN76YaRZZUkNqJ K00ZNLN76AaRZZUEMqpIin468J76PN9PN9P,..66JN8PM0HcH6SNFramRkoUkkfW2.R967uHWr ha4sF91.2ZdBZv2Y7,..ohUgZUAavgV76HTuHV86HeF,7SrePPNAv86tND,tF9ne.Ui3YhkI0G eWoWuo4aU7YdjNG2ZsB3PU7AdCFwiJr0mK0WRBZBA,98HbOGB86FNO,dDv76VN8,d7sKcDvlX. .ABH76d0EWKoVWmoam4.MO,dD2aUYe6h6kY.HnI.ZGcKoUGJEaIbCYdtCWrh66pV5Fa..0meuI eaIa0mo0mS0GrqmMqk2a.KIEKIgaIe0mWuIW0mWsC68.e0Y7uGaQbBA,N0H0HP8rFayqnuGa.M G6SU,,ABvlK4HK0GP0nIi1eKEenS2avg,S3cO,7D,dPqWm2Y2x71uIbOF6SreOv86v76DWJ,.J P8N76h,,,eqI0mWu2ME.oBA4,ND,,.Ui,HlJ0mMmGEO1PM0667uPrN1PMFR8F0Jta4MG.RN1Pc .VeQHfR..7uPPM0VN0bN1HcAHsAPM0XN0dN1H6BHMBPM03M1PM1R96xND4n4qko0GRUU.ABoB7 Ws,sFY7.MMN76HP8rlYko2Y3,PMO,,RP9in4SJYa2WrhuqK.S2f0.ErqmMaGEGob68JFTGsMGM UGMMGsMGMTGMVGMMGMVGMaGME4qhWrh0Xg2Yic9R79,7SrePML,d8HV7p7WbiVdgVB2Ze2YsR9 66v,...Q30GJaW3ZdHB7W0xVkA3UdFTsF..koA3.7OFk4q.....cP.qEH0GIqk2Wmo0GS24Pkb 8p4aEIaayEM.Uw2Y5hA..AB,d7,,JXyg5D0..eqImWehbdRZloZiohhM8PM0HN1,d8H,koUk22 U7p7MOa0W0RP9X76x76V76JN8PM0ZOF.MOiXsVUI5S2N0.koMJG3Uil4KIbgVB2Ze68HnSg3H7 6B,kSw6K3.UeB3g5.ZN8,d7,,R1...oBaGEi0H76JN83QwdONQcjphoJijZhghgmRiiQ8CIu8L qGomCrl0ksH3..RtETfPd16F9vQ59.C244.IC...Qii..70,cw7U.2.Y02.A,2U..U,Iklb8Ie pZhZJinpZHFdKLq6F6.XDJ.QiiIepZhZ7F6.Zz.E.ses,sc6.,k,,UnpZHldGrwmqmGomCb.AS .c9Ajg,0EtT.,E..W.e30E.cUX5.umUG5.70,E0E...7,,M.,.,.,tcp00kMDy.wnjl.k.E.0. 3gwP.0..I16.M.EJ.6.VQ.E..YVsH4EKithQVs9E3Qw7uPghZ,5uP..Y0,6.,..2,2.M00.lwG bHESmF3kwL,,AzJEAyIo2oe2H.BN,... --- end of encoding --- |
Автор: | Александр Ильин [ Вторник, 09 Ноябрь, 2010 13:03 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Евгений Темиргалеев писал(а): Схема (пред/пост усл. стёр, выписаны в "пробе") Опять вложенный цикл. Да что ж такое-то?UPD: Понял, здесь вложенный цикл оправдан. Правда, задача решена несколько иная. |
Автор: | Евгений Темиргалеев [ Вторник, 09 Ноябрь, 2010 13:10 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Александр Ильин писал(а): Евгений Темиргалеев писал(а): Схема (пред/пост усл. стёр, выписаны в "пробе") Опять вложенный цикл. Да что ж такое-то?![]() |
Автор: | Peter Almazov [ Вторник, 09 Ноябрь, 2010 13:21 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Alexey Veselovsky писал(а): А можно уточнить откуда что берется и что должно быть на выходе? Потому как функция без аргументов и без возвращаемого значения, которая при этом тем не менее откуда-то с потолка берет какие-то массивы, меня как-то смущает. На входе в массиве _indices лежит текущая комбинация индексов (вначале все нижние границы), на выходе там же комбинация "увеличенная на 1". Булева переменная _complete - по сути выходная, "истина" если происходит выход за границы (переполнение одометра).
|
Автор: | Александр Ильин [ Вторник, 09 Ноябрь, 2010 13:32 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Евгений Темиргалеев писал(а): Для Вас задачка по исключению :) Сейчас, вот только полный тест прогоню...
|
Автор: | Александр Ильин [ Вторник, 09 Ноябрь, 2010 13:59 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Код: MODULE PrivOdometer;
IMPORT Log; CONST arrayRank = 6; maxTestValue = 999999; (* arrayRank девяток, для теста *) VAR indices, upperBound, lowerBound: ARRAY arrayRank OF INTEGER; completed: BOOLEAN; PROCEDURE IncArray; VAR dim: INTEGER; BEGIN dim := arrayRank - 1; INC(indices[dim]); WHILE (dim > 0) & (indices[dim] > upperBound[dim]) DO DEC(dim); INC(indices[dim]) END; IF (dim = 0) & (indices[dim] > upperBound[dim]) THEN completed := TRUE ELSE INC(dim); WHILE dim < arrayRank DO indices[dim] := lowerBound[dim]; INC(dim) END END END IncArray; PROCEDURE LogIndices; VAR i: INTEGER; BEGIN FOR i := 0 TO arrayRank - 1 DO Log.Char(CHR(ORD('0') + indices[i])); END; END LogIndices; PROCEDURE DoTest (value: INTEGER; log: BOOLEAN); VAR i, v: INTEGER; BEGIN ASSERT(value >= 0, 20); ASSERT(~completed, 21); v := value; (* 'v' to 'indices' *) FOR i := arrayRank - 1 TO 0 BY -1 DO indices[i] := v MOD 10; v := v DIV 10; END; IF log THEN LogIndices; Log.String(" + 1 = "); END; IncArray; IF log THEN LogIndices; Log.Ln; END; (* 'indices' to 'v' *) v := 0; FOR i := 0 TO arrayRank - 1 DO v := 10 * v + indices[i]; END; ASSERT((v = value + 1) OR (value = maxTestValue) & completed, 60); END DoTest; PROCEDURE Test*; VAR i: INTEGER; BEGIN completed := FALSE; FOR i := 0 TO arrayRank - 1 DO upperBound[i] := 9; lowerBound[i] := 0; END; FOR i := 0 TO maxTestValue DO DoTest (i, FALSE) END; END Test; END ^Q PrivOdometer.Test |
Автор: | Александр Ильин [ Вторник, 09 Ноябрь, 2010 14:41 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Кстати, майкрософтовский вариант у меня выполняется медленнее: Код: PROCEDURE IncArray;
VAR dim, j, rank: INTEGER; BEGIN rank := arrayRank; INC(indices[rank - 1]); dim := rank - 1; WHILE dim >= 0 DO IF indices[dim] > upperBound[dim] THEN IF dim = 0 THEN completed := TRUE; RETURN END; j := dim; WHILE j < rank DO indices[j] := lowerBound[j]; INC(j) END; INC(indices[dim - 1]) END; DEC(dim) END END IncArray; |
Автор: | Peter Almazov [ Вторник, 09 Ноябрь, 2010 14:54 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Да забейте Вы на него. Представьте себе счетчик, у которого циферки справа бегут быстро, а чем левее, тем медленнее. И запрограммируйте один такт его работы. |
Автор: | Александр Ильин [ Вторник, 09 Ноябрь, 2010 14:57 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Peter Almazov писал(а): Да забейте Вы на него. Представьте себе счетчик, у которого цифорки справа бегут быстро, а чем левее, тем медленнее. И запрограммируйте один такт его работы. Ну, как бы уже сделал, если это вы мне.
|
Автор: | Сергей Губанов [ Вторник, 09 Ноябрь, 2010 15:54 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Код: PROCEDURE Inc;
PROCEDURE inc (i: INTEGER); BEGIN INC(indices[i]); IF indices[i] > upperBound[i] THEN indices[i] := lowerBound[i]; IF i > 0 THEN inc(i-1) ELSE completed := TRUE END END END inc; BEGIN inc(rank-1) END Inc; |
Автор: | Valery Solovey [ Вторник, 09 Ноябрь, 2010 15:57 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Ваша задача такая? Имеется последовательность чисел, зажатых ограничениями. Требуется к крайнему правому числу добавить единицу и, возможно, выполнить дополнительные преобразования для удовлетворения ограничений. Если я правильно понимаю ограничения, то 1. у каждого числа имеется определённый диапазон, из которого он не должен выходить 2. если появляется угроза выхода из диапазона, то данное число принимает минимально возможное значение, а к самому правому числу перед текущим прибавляется единица. Вот мой код (прошу прощения, я его не проверял, поэтому за корректность не совсем ручаюсь). Код: i := rank - 1; WHILE indices[i] = array.GetUpperBound(i) AND i >= 0 DO indices[i] := array.GetLowerBound(i); i := i - 1 END; overflow := i < 0; IF ~overflow THEN indices[i] = indices[i] + 1 END Но там прибавляется не единица. Код: i := rank - 1;
WHILE indices[i] + rank - i > array.GetUpperBound(i) AND i >= 0 DO indices[i] := array.GetLowerBound(i); i := i - 1 END; overflow := i < 0; IF ~overflow THEN indices[i] = indices[i] + rank - i END |
Автор: | Сергей Губанов [ Вторник, 09 Ноябрь, 2010 16:08 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Valery Solovey писал(а): Вот мой код (прошу прощения, я его не проверял, поэтому за корректность не совсем ручаюсь). Только сначала надо проверять i>=0, а потом индексировать, а так отличный код.Код: PROCEDURE Inc;
VAR i: INTEGER; BEGIN i := rank -1; WHILE (i >= 0) & (indices[i] = upperBound[i]) DO indices[i] := lowerBound[i]; DEC(i) END; IF i >= 0 THEN INC(indices[i]) ELSE completed := TRUE END END Inc; |
Автор: | Александр Ильин [ Вторник, 09 Ноябрь, 2010 16:21 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Valery Solovey писал(а): Ваша задача такая? Отлично! И работает ещё чуть быстрее.
|
Автор: | Valery Solovey [ Вторник, 09 Ноябрь, 2010 16:43 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Совсем забыл: у Дейксты, вроде, в книге есть похожая задача, только более общая. |
Автор: | Alexey Veselovsky [ Вторник, 09 Ноябрь, 2010 18:08 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Вот навелосипедил: Код: module Indexes (Index, incArray, test) where data Index = Index { dwnBound :: Int, value :: Int, upBound :: Int} deriving Show add n idx@(Index d v u) = ( (v'+n) `div` (u'+1), idx {value = (v'+n) `mod` (u'+1) + d} ) where d' = 0 v' = v-d u' = u-d incArray idxs = idxs' where (_,idxs') = foldl (\(a,ix) i -> case (add a i) of (a',i') -> (a',i':ix)) (1,[]) (reverse idxs) test = incArray [Index 0 8 9, Index 0 9 9] Пойду теперь гляну как это сделано в стандартной либе ![]() |
Автор: | Alexey Veselovsky [ Вторник, 09 Ноябрь, 2010 19:22 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Вообще, на самом деле, для обхода многомерного массива эта функция совершенно не нужна. Обходится многомерный массив как-то так: Код: process f acc arr = foldl f acc (elems arr)
|
Автор: | Valery Solovey [ Вторник, 09 Ноябрь, 2010 19:25 ] |
Заголовок сообщения: | Re: Еще один этюд: пошаговый обход многомерного массива |
Код: -module(arr).
-export([next/1]). next([]) -> io:format("~p~n", [overflow]), []; next([{Min, Cur, Max}| Tail]) -> % список заранее развёрнут (reverse/1). if Cur + 1 > Max -> [{Min, Min, Max} | next(Tail)]; Cur + 1 =< Max -> [{Min, Cur + 1, Max} | Tail] end. |
Страница 1 из 2 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |