Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. The Lounge
  3. Nested loops

Nested loops

Scheduled Pinned Locked Moved The Lounge
questionlounge
74 Posts 34 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R R Erasmus

    Refer to: http://en.wikipedia.org/wiki/Cyclomatic_complexity[^] more specifically the section on "Implications for Software Testing", for a better understanding from where I'm coming from.

    "Program testing can be used to show the presence of bugs, but never to show their absence." << please vote!! >>

    S Offline
    S Offline
    Stefan_Lang
    wrote on last edited by
    #49

    Interesting article. However, according to these definitions a triple nested loop only has a complexity of 4, and the inventer suggested to break up code when exceeding a maximum complexity of 10(!).

    (1)->(2)->(3)->(4)->(5)->(6)->(7)->(8)
    ^ ^ ^ | | |
    | | | | | |
    | | (9)<--- | |
    | (0)<------------- |
    (a)<-----------------------

    M = E − N + 2P = 13 - 11 + 2\*1 = 4
    

    Also, extracting the inner loop into a separate function does not even help, as it increases P:

    (1)->(2)->(3)---(call)-->(4)->(5)->(6)
    ^ ^ | |
    | | | |
    | (7)<------------- |
    (8)<-----------------------

    M1 = E1 − N1 + 2P1 = 9 - 8 + 2\*1 = 3
    

    (1)->(2)->(3)->(4)
    ^ |
    | |
    (5)<---

    M2 = E2 − N2 + 2P2 = 5 - 5 + 2\*1 = 2
    

    and
    M = E - N + 2P = 14 - 13 +2*2 = 5

    So, by extracting a loop into another function, you are actually increasing the complexity, instead of reducing it!

    R 1 Reply Last reply
    0
    • S Stefan_Lang

      Interesting article. However, according to these definitions a triple nested loop only has a complexity of 4, and the inventer suggested to break up code when exceeding a maximum complexity of 10(!).

      (1)->(2)->(3)->(4)->(5)->(6)->(7)->(8)
      ^ ^ ^ | | |
      | | | | | |
      | | (9)<--- | |
      | (0)<------------- |
      (a)<-----------------------

      M = E − N + 2P = 13 - 11 + 2\*1 = 4
      

      Also, extracting the inner loop into a separate function does not even help, as it increases P:

      (1)->(2)->(3)---(call)-->(4)->(5)->(6)
      ^ ^ | |
      | | | |
      | (7)<------------- |
      (8)<-----------------------

      M1 = E1 − N1 + 2P1 = 9 - 8 + 2\*1 = 3
      

      (1)->(2)->(3)->(4)
      ^ |
      | |
      (5)<---

      M2 = E2 − N2 + 2P2 = 5 - 5 + 2\*1 = 2
      

      and
      M = E - N + 2P = 14 - 13 +2*2 = 5

      So, by extracting a loop into another function, you are actually increasing the complexity, instead of reducing it!

      R Offline
      R Offline
      R Erasmus
      wrote on last edited by
      #50

      "One common testing strategy, espoused for example by the NIST Structured Testing methodology, is to use the cyclomatic complexity of a module to determine the number of white-box tests that are required to obtain sufficient coverage of the module." The word module that they are referring to is basically a function. So the complexity generally gets measured on the function and not the whole program. Therefor braking a nested if into function calls will actually reduce/spread the complexity of each function making them simpler and easier to test. So instead of having one function with example a complexity of 25, you'll have 3 functions with a complexity of 10 each.

      "Program testing can be used to show the presence of bugs, but never to show their absence." << please vote!! >>

      S 1 Reply Last reply
      0
      • T TheGreatAndPowerfulOz

        That's just silly. Use as many nested loops as required for the algorithm and no more. It may be possible to re-factor and re-engineer the algorithm to make fewer loops, but that may make the code more complex, and harder to understand. Judicious use of The KISS principle is, I think, best.

        If your actions inspire others to dream more, learn more, do more and become more, you are a leader." - John Quincy Adams
        You must accept one of two basic premises: Either we are alone in the universe, or we are not alone in the universe. And either way, the implications are staggering” - Wernher von Braun

        B Offline
        B Offline
        Brad Stiles
        wrote on last edited by
        #51

        As many as necessary. And remember that code you call may itself have loops, so those should be considered nested as well. Refactoring nested loop to another method, class or module doesn't change the fact that it's nested.

        Currently reading: "The Prince", by Nicolo Machiavelli

        1 Reply Last reply
        0
        • R R Erasmus

          "One common testing strategy, espoused for example by the NIST Structured Testing methodology, is to use the cyclomatic complexity of a module to determine the number of white-box tests that are required to obtain sufficient coverage of the module." The word module that they are referring to is basically a function. So the complexity generally gets measured on the function and not the whole program. Therefor braking a nested if into function calls will actually reduce/spread the complexity of each function making them simpler and easier to test. So instead of having one function with example a complexity of 25, you'll have 3 functions with a complexity of 10 each.

          "Program testing can be used to show the presence of bugs, but never to show their absence." << please vote!! >>

          S Offline
          S Offline
          Stefan_Lang
          wrote on last edited by
          #52

          That's what I thought at first, too. But then, what is P?

          R 1 Reply Last reply
          0
          • S Simon_Whale

            for me personally if you are at a point of needing to deeper than two levels then you need to rethink the approach

            Lobster Thermidor aux crevettes with a Mornay sauce, served in a Provençale manner with shallots and aubergines, garnished with truffle pate, brandy and a fried egg on top and Spam - Monty Python Spam Sketch

            F Offline
            F Offline
            Fabio Franco
            wrote on last edited by
            #53

            How about 3D plotting? Do we imagine the third axis?

            "To alcohol! The cause of, and solution to, all of life's problems" - Homer Simpson "Our heads are round so our thoughts can change direction." ― Francis Picabia

            S 1 Reply Last reply
            0
            • F Fabio Franco

              How about 3D plotting? Do we imagine the third axis?

              "To alcohol! The cause of, and solution to, all of life's problems" - Homer Simpson "Our heads are round so our thoughts can change direction." ― Francis Picabia

              S Offline
              S Offline
              Simon_Whale
              wrote on last edited by
              #54

              I've never been involved with 3d printing, at the moment I work on insurance solutions. So to be honest I wouldn't have the first clue where to start

              Lobster Thermidor aux crevettes with a Mornay sauce, served in a Provençale manner with shallots and aubergines, garnished with truffle pate, brandy and a fried egg on top and Spam - Monty Python Spam Sketch

              1 Reply Last reply
              0
              • L Lost User

                Follow up on the Variable names thread below, I would like to ask what is the level of nested loops that is acceptable in general? Most people would agree that three levels is acceptable, but I would say stop at two. The third loops gets a bit messy.

                for(int i=0; i<100; i++) { //Okay
                for(int j=0; j<100; j++) { //Acceptable
                for(int k=0; k<100; k++) { //Messy
                }
                }
                }

                K Offline
                K Offline
                Kieryn Phipps
                wrote on last edited by
                #55

                I have a razor view for a model that contains categories, sub-categories and then the items. That's a 3 level foreach right there. Personally I don't think it's messy. Maybe the sub-categories could be refactored to a separate partial, but seeing as for now this is the only view using them I see no reason to do that:

                var subCategoryGroups = Model.GroupBy(r => new { r.Category, r.SubCategory });
                var categoryGroups = subCategoryGroups.GroupBy(r => r.Key.Category);

                foreach (var catGroup in categoryGroups)
                {

                @catGroup.Key

                        @foreach (var subCatGroup in catGroup)
                        {
                

                @subCatGroup.Key.SubCategory

                                @foreach (var item in subCatGroup)
                                {        
                                
                
                                        @Html.ActionLink(item.DisplayName,
                                            "RunReport", new { item.ReportProcedureId })
                                
                
                                }
                            
                
                        
                
                        }            
                

                }

                1 Reply Last reply
                0
                • S Stefan_Lang

                  That's what I thought at first, too. But then, what is P?

                  R Offline
                  R Offline
                  R Erasmus
                  wrote on last edited by
                  #56

                  "For a single program (or subroutine or method), P is always equal to 1." Thus each function without having any loops/if-statements ect. starts with a complexity of 1.

                  "Program testing can be used to show the presence of bugs, but never to show their absence." << please vote!! >>

                  1 Reply Last reply
                  0
                  • L Lost User

                    Follow up on the Variable names thread below, I would like to ask what is the level of nested loops that is acceptable in general? Most people would agree that three levels is acceptable, but I would say stop at two. The third loops gets a bit messy.

                    for(int i=0; i<100; i++) { //Okay
                    for(int j=0; j<100; j++) { //Acceptable
                    for(int k=0; k<100; k++) { //Messy
                    }
                    }
                    }

                    T Offline
                    T Offline
                    thoiness
                    wrote on last edited by
                    #57

                    The answer relates to performance. How does the nested loops effect performance? If it negatively impacts performance, can you refactor to get the same results with an increase in performance? If the answer is that it is negligible, and the code is easily comprehended, then how can you put a limit on what you genuinely need? If you were to unravel a three dimensional array in an application, would not three nested loops make sense? If not, then what? Would a series of self-pointing functions make more sense, have better performance, or be easier to read? I'd say no to all three points.

                    1 Reply Last reply
                    0
                    • T TheGreatAndPowerfulOz

                      Making an arbitrary rule to have no more than one nested loop (two loops) *is* indeed a silly rule. See here[^] for an example where your arbitrary rule makes no sense. Your data structures, or database, or whatever may require more looping. Unrolling such loops usually results in harder-to-understand and often less efficient code. It may not be possible to re-engineer or re-factor the code without redoing the entire system. Often an unachievable goal for legacy and cost reasons. If this is a new system, then yeah, by all means go for it, if possible and truly better. I have found that often, it's not really better. See

                      If your actions inspire others to dream more, learn more, do more and become more, you are a leader." - John Quincy Adams
                      You must accept one of two basic premises: Either we are alone in the universe, or we are not alone in the universe. And either way, the implications are staggering” - Wernher von Braun

                      A Offline
                      A Offline
                      Alan Balkany
                      wrote on last edited by
                      #58

                      Every situation is different, but too many levels of loops can overwhelm the maintenance programmer with complexity. Functions/methods exist to chop the logic into manageable chunks. After the first couple of loops, the rest can be abstracted away into a subroutine. This makes the function understandable, and if more detail is needed the subroutine can then optionally be examined.

                      "Microsoft -- Adding unnecessary complexity to your work since 1987!"

                      1 Reply Last reply
                      0
                      • T TheGreatAndPowerfulOz

                        That's just silly. Use as many nested loops as required for the algorithm and no more. It may be possible to re-factor and re-engineer the algorithm to make fewer loops, but that may make the code more complex, and harder to understand. Judicious use of The KISS principle is, I think, best.

                        If your actions inspire others to dream more, learn more, do more and become more, you are a leader." - John Quincy Adams
                        You must accept one of two basic premises: Either we are alone in the universe, or we are not alone in the universe. And either way, the implications are staggering” - Wernher von Braun

                        S Offline
                        S Offline
                        SeattleC
                        wrote on last edited by
                        #59

                        ahmed zahmed wrote:

                        Use as many nested loops as required for the algorithm and no more.

                        I totally agree. But... One loop makes a problem linear on the number of items in the loop. Two loops generally makes it O(n squared). Three loops makes it O(n cubed). In most practical cases, once you get to three nested loops, you need to ask yourself, "Am I using an efficient algorithm to compute this result?" While there exist O(n cubed) algorithms, in the workaday world, you usually don't see them. Another thing, multiply nested loops so often happen because somebody didn't really understand lwhat they were iterating over. Many a gnarly function of hundreds of lines and loops nested three or four deep have I analyzed and converted to a far simpler form. The deep nesting is often a signal that you're "doing it wrong".

                        1 Reply Last reply
                        0
                        • L Lost User

                          Follow up on the Variable names thread below, I would like to ask what is the level of nested loops that is acceptable in general? Most people would agree that three levels is acceptable, but I would say stop at two. The third loops gets a bit messy.

                          for(int i=0; i<100; i++) { //Okay
                          for(int j=0; j<100; j++) { //Acceptable
                          for(int k=0; k<100; k++) { //Messy
                          }
                          }
                          }

                          J Offline
                          J Offline
                          jschell
                          wrote on last edited by
                          #60

                          Shameel wrote:

                          Most people would agree that three levels is acceptable, but I would say stop at two.

                          Not sure I have ever seen three. Certainly not recently. If I did it was only because it was spanning an array with 3 dimensions. I very seldom encounter two. I suspect that if this is something that you see more often than say once a year then someone is designing something wrong or your problem domain space itself leads to solutions that requires that. If the first then it is a design problem not a code problem. If the second then I would suspect that those working in that space should be comfortable with that idiom (more so than working in other domains) so it isn't a problem.

                          1 Reply Last reply
                          0
                          • T TheGreatAndPowerfulOz

                            That's just silly. Use as many nested loops as required for the algorithm and no more. It may be possible to re-factor and re-engineer the algorithm to make fewer loops, but that may make the code more complex, and harder to understand. Judicious use of The KISS principle is, I think, best.

                            If your actions inspire others to dream more, learn more, do more and become more, you are a leader." - John Quincy Adams
                            You must accept one of two basic premises: Either we are alone in the universe, or we are not alone in the universe. And either way, the implications are staggering” - Wernher von Braun

                            F Offline
                            F Offline
                            Florin Jurcovici 0
                            wrote on last edited by
                            #61

                            I like short functions - anything longer than 10 lines is suspicious, IMO, and I never encountered a case where I absolutely needed more than 200 lines in one function. If you have three levels of nesting, there's place for extracting a function, giving it a decent, speaking and reasonable name (occasionally a long one, but that's IMO still better than writing comments - compilers don't check comments). Thus, I'd say nesting beyond three is rarely justified. And extracting smaller functions just makes the code better readable, not worse.

                            T J 2 Replies Last reply
                            0
                            • S Stefan_Lang

                              mark merrens wrote:

                              c) Two: anything else is lunacy and must be stamped out: 2 dimensions is more than enough for anybody!

                              That statement pretty much reminds me of

                              someone once supposedly said:

                              No one will ever need more than 640KB of memory

                              In geometry, I can easily think of problems that require 6 or more nested loops. In tensor analysis, double that. I could imagine that top notch physicists and mathematicians may need even more, occasionally. How do you think they model their ideas about 10-, 20- or higher-dimensional space-time? You can not refactor away the need for a nested loop. End of story.

                              F Offline
                              F Offline
                              Florin Jurcovici 0
                              wrote on last edited by
                              #62

                              Suppose you have some operation operating on multidimensional arrays. You don't write distinct versions for each number of dimensions, you use recursion. Recursion for such cases doesn't require more than one nesting level.

                              S 1 Reply Last reply
                              0
                              • L Lost User

                                for (int index = 0; index < 1000000; index++)
                                {
                                int k = index % 100;
                                int j = (index / 100) % 100;
                                int i = index / 10000;
                                }

                                Don't think so. That might be the worst possible way to do it.

                                for (int i = 0; i < 100; i++)
                                {
                                innerLoop(i);
                                }

                                Great. So you thought you found the actual logic? Nope, Chuck Testa a useless outer loop that tells you nothing about what's going on. This might work if you have code bubbles[^], but otherwise it's like you have to keep turning stones one by one until you finally find the interesting part. It's probably the "accepted way" anyway, but it sucks. Any possible way to do this sucks. Fortunately it's not very common.

                                F Offline
                                F Offline
                                Florin Jurcovici 0
                                wrote on last edited by
                                #63

                                You assume innerLoop() is what the inner loop should be. Suppose you need to multiply an n-dimensional array by a constant. How about multiplySliceBy(index, mutiplier)? As long as you have mulitplySliceBy() defined for with dimension count from 1 up to an arbitrary upper limit, I think it's speaking code.

                                L 1 Reply Last reply
                                0
                                • H hairy_hats

                                  If that's in your satnav you must have to drive really slowly for all those nested function calls to complete before you arrive at wherever you wanted it to direct you to.

                                  F Offline
                                  F Offline
                                  Florin Jurcovici 0
                                  wrote on last edited by
                                  #64

                                  That was the case with ancient compilers/interpreters. Nowadays function calls are cheap in most cases (unless you put huge frames on the stack - i.e. your functions have very long parameter lists (I mean, several dozen parameters). If you're smart and put all parameters except the loop counters/indexes in a struct, you only need to pass a pointer to the struct - it's something pointer-like even when you pass the object in C# or Java, so it can be made very cheap. In C++, you can declare the functions inline, which will tell the compiler to produce code as if there weren't any functions. Thus, you get the best of for everybody: optimized code for the computer and readable code for human readers.

                                  S 1 Reply Last reply
                                  0
                                  • F Florin Jurcovici 0

                                    You assume innerLoop() is what the inner loop should be. Suppose you need to multiply an n-dimensional array by a constant. How about multiplySliceBy(index, mutiplier)? As long as you have mulitplySliceBy() defined for with dimension count from 1 up to an arbitrary upper limit, I think it's speaking code.

                                    L Offline
                                    L Offline
                                    Lost User
                                    wrote on last edited by
                                    #65

                                    Ok that could work in that case.

                                    1 Reply Last reply
                                    0
                                    • F Florin Jurcovici 0

                                      I like short functions - anything longer than 10 lines is suspicious, IMO, and I never encountered a case where I absolutely needed more than 200 lines in one function. If you have three levels of nesting, there's place for extracting a function, giving it a decent, speaking and reasonable name (occasionally a long one, but that's IMO still better than writing comments - compilers don't check comments). Thus, I'd say nesting beyond three is rarely justified. And extracting smaller functions just makes the code better readable, not worse.

                                      T Offline
                                      T Offline
                                      TheGreatAndPowerfulOz
                                      wrote on last edited by
                                      #66

                                      moving code of inner loops into functions doesn't reduce the nestedness, often complicates the understanding and seldom makes things simpler.

                                      If your actions inspire others to dream more, learn more, do more and become more, you are a leader." - John Quincy Adams
                                      You must accept one of two basic premises: Either we are alone in the universe, or we are not alone in the universe. And either way, the implications are staggering” - Wernher von Braun

                                      1 Reply Last reply
                                      0
                                      • S Simon_Whale

                                        for me personally if you are at a point of needing to deeper than two levels then you need to rethink the approach

                                        Lobster Thermidor aux crevettes with a Mornay sauce, served in a Provençale manner with shallots and aubergines, garnished with truffle pate, brandy and a fried egg on top and Spam - Monty Python Spam Sketch

                                        S Offline
                                        S Offline
                                        StephenPhillips
                                        wrote on last edited by
                                        #67

                                        'tis said by Linus Torvalds that "If you need more than 3 levels of indentation, you're screwed anyway, and should fix your program."[^] While this is a quote from 1995, it is certainly a guideline worth thinking about. When you have many levels of nesting, what are the options? - Collapse your 2D array into a flat array and reference using a multiplicative index (much like the underlying work done with a 2D array anyway) - Call a function when at a given depth, splitting the complexity into separate pieces and cutting the indentation. - Rework the program logic to require less indentation in the first place, such as using external variables or handling exceptions separately. These all have their good and bad points, and as always it depends on circumstances. As people here have pointed out, situations such as iterating across 3D constructs does often require additional levels of indentation to use. It's down to the situation at hand; if it makes things easier to read/maintain, then simplify things where you can. If "simpler" is more twisty and fragmented, then just tolerate the extra indentation and get back to work.

                                        Sometimes a fist in the face says more than a thousand honeyed words.

                                        1 Reply Last reply
                                        0
                                        • L Lost User

                                          Follow up on the Variable names thread below, I would like to ask what is the level of nested loops that is acceptable in general? Most people would agree that three levels is acceptable, but I would say stop at two. The third loops gets a bit messy.

                                          for(int i=0; i<100; i++) { //Okay
                                          for(int j=0; j<100; j++) { //Acceptable
                                          for(int k=0; k<100; k++) { //Messy
                                          }
                                          }
                                          }

                                          S Offline
                                          S Offline
                                          scramjetter
                                          wrote on last edited by
                                          #68

                                          I always use one more than necessary:

                                          for($ocd=0; $ocd

                                          But other than that one special idiosyncrasy, as many loops that are necessary. It's helpful to use Iterators whenever possible, for languages that support them. Three loops are what I typically see.

                                          1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups