15 Replies
      Latest reply on Mar 24, 2020 4:51 PM by G.U.T.explorer
      G.U.T.explorer Level 1 Level 1 (0 points)

        This comes up a lot (for years) and has me buggered. 

         

        1. class Act: Codable {
        2.    var a:  Uint32
        3.    var b: [UInt32]?
        4. .
        5. .
        6. .
        7.    var z: [UInt32]?
        8.    init( ...vars...)
        9. }

         

        I want to do a simple sum on .nonzerobitCount for every var a through z.

         

        I can write code to check,e.g.,

         

        10. if Act.b != nil {for index in 0..<Act.b!.count { if Act.b?[index] != nil { totalBits += Act.b?[index].nonzeroBiCount } } }

         

        but even with copy and paste this is exhausting and cludgy.

        • Re: how to loop through array(s) of optionals
          Claude31 Level 8 Level 8 (9,135 points)

          All var are arrays, except a. Is it on purpose ?

           

          I want to do a simple sum on .nonzerobitCount for every var a through z.

          What do you want to count exactly

          Is it ?

                  var totalBits = 0
                  if b != nil {
                      for index in 0 ..< b!.count {
                          if b?[index] != nil {
                              totalBits += b?[index].nonzeroBitCount
                          }
                      }
                  }
                  if c != nil {
                      for index in 0 ..< c!.count {
                          if c?[index] != nil {
                              totalBits += c?[index].nonzeroBitCount
                          }
                      }
                  }
               // repeat until z

           

          line 04:

          - b is not nil so b? is useless, use b!

          - how could b![index] be nil ?

          line 05:

          - you had a typo : nonzeroBiCount instead of nonzeroBitCount

           

          I would do the following

           

                  var totalBits = 0
                  var b: [UInt32]?
                  var c: [UInt32]?
                  var d: [UInt32]?
                  var z: [UInt32]?
                  var bToz : [[UInt32]?] = [b, c, d, z]     // You have to type all var names
                 
                  for xx in bToz {
                      if xx != nil {
                          for index in 0 ..< xx!.count {
                              totalBits += xx![index].nonzeroBitCount
                          }
                      }
                  }

           

          Hope I understood your request

            • Re: how to loop through array(s) of optionals
              Claude31 Level 8 Level 8 (9,135 points)

              Some refinement to simplify:

               

                     for xx in bToz {
                          if xx != nil {
                              for item in  xx! {
                                  totalBits += item.nonzeroBitCount
                              }
                          }
                      }

               

              or

               

              for xx in bToz where xx != nil {
                  totalBits += xx!.reduce(0) { $0 + $1.nonzeroBitCount }
              }
              • Re: how to loop through array(s) of optionals
                G.U.T.explorer Level 1 Level 1 (0 points)

                I have rechecked my code, you are right about line 04 being useless, b[index] cannot be nil because it was included in the Act.b!.count.

                Thanks!

                • Re: how to loop through array(s) of optionals
                  G.U.T.explorer Level 1 Level 1 (0 points)

                  I took a closer look at your line 06

                  " var bToz : [[UInt32]?] = [b, c, d, z]     // You have to type all var names "

                  If I make Act.a:[UInt32], even though it would hold just one UInt32, a var aToz could be added within the class declaration:

                       var aToz: [[UInt32]?] { return [ a, b, c, d...., z] } 

                  The beauty of which is that it needs no initializer, so my init's throughout the code are not affected.  All I had to do was put brackets, [ ], around every existing reference to Act.a     Not as painful as I thought it might be.

                   

                  Thanks for the inspiration!

                    • Re: how to loop through array(s) of optionals
                      G.U.T.explorer Level 1 Level 1 (0 points)

                      Just to be clear, I can now code a for-loop to go through just-the-vars-I-want:

                       

                      1. class Act: Codable {
                      2.    var a: [Uint32]
                      3.    var b: [UInt32]?
                      4. ...
                      5.   var z: [UInt32]?
                      6.   var aToz: [[UInt32]?] { return [ a, b, c, d...., z] }
                      7.    init( ...vars...)
                      8. }

                      ...

                      100.     for member in Act.aToz { if member != nil {for index in 0..<member!.count { totalBits += member?[index].nonzeroBitCount } } }

                       

                      A further benefit is that when my "class Act" is written to a JSON file, the computed var "aToz" is not in it, not even a mention of it.  So the file size is not "doubled" by adding the computed var!  Love it.

                       

                      I want to rework : "let totalBits = act.b?.reduce(0, {$0 + $1.nonzeroBitCount}) ?? 0" and use it eventually... it's beautiful!

                  • Re: how to loop through array(s) of optionals
                    OOPer Level 8 Level 8 (6,095 points)

                    First of all, you should better re-consider if you really need Optional Arrays.

                    But that's another issue and you may need it in some cases.

                     

                    If I were given an Optional Array, I would write something like this:

                        var totalBits: Int = 0
                        for element in act.b ?? [] {
                            totalBits += element.nonzeroBitCount
                        }
                    
                    

                     

                    Or, you can write it in a single line if you are familiar with `reduce`:

                        let totalBits = act.b?.reduce(0, {$0 + $1.nonzeroBitCount}) ?? 0
                    
                    

                     

                    When multiple Optional Arrays given, this would work:

                        let totalBits = [act.b ?? [], /* ...,*/ act.z ?? []].joined().reduce(0, {$0 + $1.nonzeroBitCount})
                    
                    
                    • Re: how to loop through array(s) of optionals
                      G.U.T.explorer Level 1 Level 1 (0 points)

                      in order of response:

                      to Claude31:

                      • line 04:
                        - b is not nil so b? is useless, use b!
                        - how could b![index] be nil ?

                      It might be that not all b are occupied, e.g., just the first in the array.  My fault for not specifying every detail: towit, e.g., b can have up to four members in the array, or none.

                      • line 05:
                        - you had a typo : nonzeroBiCount instead of nonzeroBitCount

                      Sorry, yes a typo.  This is not copied directly from my code but constructed just for this inquiry.

                       

                      to OOper:

                      Yeah... I can't think of another way to "not use optional arrays".

                      I love seeing your mystical syntax code.  I'll try it.  I'm not fluent with closures.  I've used them of course, but still find them mystical.

                       

                      to all:

                      I have failed in my request. 

                      I am looking for a way to "for loop" through Act's vars [a, b, c, ...,z] so I can apply any of the above methods.

                      I have tried in vain to use enum.

                      I have also considered making the vars a...z another level in the array so that the class Act has just one var, call it alpha then I could:

                      for mychar in alpha{ insert line 10 here }

                      But this would be a major rewrite of my app.  I thought there might be a better way to loop through the members of the class.

                        • Re: how to loop through array(s) of optionals
                          Claude31 Level 8 Level 8 (9,135 points)
                          • line 04:
                            - b is not nil so b? is useless, use b!
                            - how could b![index] be nil ?

                          It might be that not all b are occupied, e.g., just the first in the array.  My fault for not specifying every detail: towit, e.g., b can have up to four members in the array, or none.

                           

                          b is an optional array (not an array of optionals.

                          So if b is not nil, b![index] cannot be nil ; it can crash for out of bounds index, but not be nil.

                           

                          I tested the exact following code in playground, to loop through all vars (from b to z)

                          I renamed vars as bB, cC… because I already used b, c…:

                           

                          var totalBits = 0
                          var bB: [UInt32]?
                          var cC: [UInt32]? = [125]
                          var dD: [UInt32]?
                          var zZ: [UInt32]? = [4123]
                          var bToz : [[UInt32]?] = [bB, cC, dD, zZ]     // You have to type all var names
                          
                          for xx in bToz {
                              if xx != nil {
                                  for index in 0 ..< xx!.count {
                                      totalBits += xx![index].nonzeroBitCount
                                  }
                              }
                          }
                          print(totalBits)
                          totalBits = 0
                          for xx in bToz {
                               if xx != nil {
                                   for item in  xx! {
                                       totalBits += item.nonzeroBitCount
                                   }
                               }
                          }
                          print(totalBits)
                          totalBits = 0
                          for xx in bToz where xx != nil {
                              totalBits += xx!.reduce(0) { $0 + $1.nonzeroBitCount }
                          }
                          print(totalBits)

                           

                           

                          I get the following correct results:

                          11

                          11

                          11

                            • Re: how to loop through array(s) of optionals
                              G.U.T.explorer Level 1 Level 1 (0 points)

                              "b is an optional array (not an array of optionals."

                              UhOh.  You're right again.  I have to rethink this. The array Act.a must exist and be non-nil, but all other vars Act.b thru z need not have values.  Nor arrays then?  Might I need optional arrays of optionals?  Now I feel like I stepped in something.  :-(

                                • Re: how to loop through array(s) of optionals
                                  Claude31 Level 8 Level 8 (9,135 points)

                                  You need to be very clear on what you get in var a to z.

                                  Where are those UInt coming from ?

                                  Optional are useful if you need to have a value:

                                  - for instance, if each var was to contain exactly 6 items, you could declare the arrays as [UInt32?]

                                  - but in that case, the array itself doesn't need to be optional

                                   

                                  In your case, I understand you will have a variable number of items in arrays:

                                  - a will have one,

                                  - b may have 6

                                  - c may have 0.

                                  But all var a, b, c exist.

                                  So, no need to be optional, but just declare initially as empty (hence no init needed):

                                  var a : [UInt32] = []. // or var a = [UInt32]()

                                   

                                  With this, your code becomes (tested in playground):

                                  var totalBits = 0
                                  var a: [UInt32] = []
                                  var b: [UInt32] = []
                                  var c: [UInt32] = []
                                  var d: [UInt32] = []
                                  var z: [UInt32] = []
                                  var aToz : [[UInt32]] = []     // You have to type all var names
                                   
                                  func computeTotal() -> Int {
                                       var total = 0
                                       for xx in aToz {
                                           total += xx.reduce(0) { $0 + $1.nonzeroBitCount }
                                       }
                                      return total
                                  }
                                  
                                  // Somewhere, you will populate the arrays (getting a JSON Request, typing by user, … whatever way ; here I set manually)
                                  func populateVar() {
                                        a = [100]
                                        b = [50, 200]
                                        c = [125, 6, 314]
                                        d = []
                                        z = [4123]
                                        aToz = [a, b, c, d, z]     // You have to type all var names
                                   
                                       totalBits = computeTotal()
                                       print(totalBits)
                                  }
                                   
                                  populateVar()

                                  I get the result in log:

                                  27

                                   

                                  As a conclusion

                                  It is better here to have the same type for all, even to hold a single value or no value.

                                  Globally, you should avoid adding optional everywhere

                                    • Re: how to loop through array(s) of optionals
                                      G.U.T.explorer Level 1 Level 1 (0 points)

                                      I tried using optional arrays of optionals.  It just made my code messy.  It was easier to deal with a formed array that had a zero value than add a couple hundred "!" to optionals calls.

                                       

                                      btw: the code "var aToz : [[UInt32]] = []" may work outside a class declaration, as in a playground, but fails within one.

                                       

                                      "     var aToz: [[UInt32]?] { return [ a, b, c, d...., z] }     " works inside a class.  You lead me to that and I am thankful.  My code works now.

                                        • Re: how to loop through array(s) of optionals
                                          Claude31 Level 8 Level 8 (9,135 points)

                                          I don't understand your points:

                                           

                                          • I tried using optional arrays of optionals.  It just made my code messy.  It was easier to deal with a formed array that had a zero value than add a couple hundred "!" to optionals calls.

                                           

                                          I just proposed to REMOVE optionals

                                           

                                          • btw: the code "var aToz : [[UInt32]] = []" may work outside a class declaration, as in a playground, but fails within one.

                                           

                                          I just tested 1 minute ago, in a class or inside a func, it works perfectly OK of course.

                                          But you need to initialize its content somewhere.

                                          What is the error you get to understand the error you made ?

                                           

                                          Anyway, it is good to know it works, don't forget to close the thread.

                                            • Re: how to loop through array(s) of optionals
                                              G.U.T.explorer Level 1 Level 1 (0 points)

                                              I stand corrected.  I just copied and pasted "var aToz : [[UInt32]] = []" into my class and it was accepted this time.  Don't know what i did the first time.

                                              As for the optionals: my actual code creates UInt32=zero for a finite number of members of any array that has at least one real value.  So if a given array has just one real value the other members get zero, and it is easier to if=zero than to optionalize (to nil)... you know what I mean, and then if!=nil.  Maybe that's as clear as mud but without showing the actual code it would take too much explaining.

                                               

                                              As for "initializing the  content" of the aToz, thats what "var aToz: [[UInt32]?] { return [a, b, c, ... z] } " does.  That is to say, the closure does the initialization, as I understand it.

                                               

                                              My happy results are found @: G.U.T.explorerMar 24, 2020 9:42 AM