8 Replies
      Latest reply on Mar 26, 2020 8:28 AM by waynehend
      waynehend Level 1 Level 1 (5 points)

        A "normal" for..in loop on an array handles the elements in the order you would expect.  But not this one.

         

        Go ahead and try this in a playground.  Every time it runs, I get a different ordering of the keys and never get back 1,2,3,4,5 as entered.  If I make another loop around the loop shown (as commented out), it'll give the same key order for each iteration.  But a different key order appears when the whole thing is rerun.

         

        Confused.

         

        import UIKit
        
        let dataTable: [String: [Double]] = [
        "1Cat": [99.95, 0, 0.05, 0, 0, 0, 0.04],
        "2Dog": [1, 1, 0, 98, 0, 0, 0.2],
        "3Mouse": [49.0, 43.2, 3.9, 0, 0.2, 3.7, 0.05],
        "4Gerbil": [40.3, 55.4, 3.0, 0, 0.4, 0.9, 0.05],
        "5Fish": [7.7, 90.8, 1.2, 0, 0.1, 0.2, 0.05]]
        
        for i in dataTable {
            print(i)
        }
        
        // for j in 1...4 {
        // for i in dataTable {
        //    print(i)
        // }
        //    print("\n")
        // } 
        
        
        • Re: Unexpected for...in array behavior
          Claude31 Level 8 Level 8 (9,205 points)

          I don't understand your point

           

          I ran this:

          let dataTable: [String: [Double]] = [
          "1Cat": [99.95, 0, 0.05, 0, 0, 0, 0.04],
          "2Dog": [1, 1, 0, 98, 0, 0, 0.2],
          "3Mouse": [49.0, 43.2, 3.9, 0, 0.2, 3.7, 0.05],
          "4Gerbil": [40.3, 55.4, 3.0, 0, 0.4, 0.9, 0.05],
          "5Fish": [7.7, 90.8, 1.2, 0, 0.1, 0.2, 0.05]]
           
          for i in dataTable {
              print(i)
          }
           
          print("\n Second form\n")
          for j in 1...4 {
              for i in dataTable {
                  print(i)
              }
              print("\n")
          } 

           

          And got same results for each:

          (key: "4Gerbil", value: [40.3, 55.4, 3.0, 0.0, 0.4, 0.9, 0.05])

          (key: "1Cat", value: [99.95, 0.0, 0.05, 0.0, 0.0, 0.0, 0.04])

          (key: "3Mouse", value: [49.0, 43.2, 3.9, 0.0, 0.2, 3.7, 0.05])

          (key: "2Dog", value: [1.0, 1.0, 0.0, 98.0, 0.0, 0.0, 0.2])

          (key: "5Fish", value: [7.7, 90.8, 1.2, 0.0, 0.1, 0.2, 0.05])

           

          Second form

           

          (key: "4Gerbil", value: [40.3, 55.4, 3.0, 0.0, 0.4, 0.9, 0.05])

          (key: "1Cat", value: [99.95, 0.0, 0.05, 0.0, 0.0, 0.0, 0.04])

          (key: "3Mouse", value: [49.0, 43.2, 3.9, 0.0, 0.2, 3.7, 0.05])

          (key: "2Dog", value: [1.0, 1.0, 0.0, 98.0, 0.0, 0.0, 0.2])

          (key: "5Fish", value: [7.7, 90.8, 1.2, 0.0, 0.1, 0.2, 0.05])

           

          SAME AFTER 3 times

           

          I assume the same for you ?

           

          Did a second run and got a different key ordezr:

          (key: "2Dog", value: [1.0, 1.0, 0.0, 98.0, 0.0, 0.0, 0.2])

          (key: "3Mouse", value: [49.0, 43.2, 3.9, 0.0, 0.2, 3.7, 0.05])

          (key: "1Cat", value: [99.95, 0.0, 0.05, 0.0, 0.0, 0.0, 0.04])

          (key: "4Gerbil", value: [40.3, 55.4, 3.0, 0.0, 0.4, 0.9, 0.05])

          (key: "5Fish", value: [7.7, 90.8, 1.2, 0.0, 0.1, 0.2, 0.05])

           

          Second form

           

          (key: "2Dog", value: [1.0, 1.0, 0.0, 98.0, 0.0, 0.0, 0.2])

          (key: "3Mouse", value: [49.0, 43.2, 3.9, 0.0, 0.2, 3.7, 0.05])

          (key: "1Cat", value: [99.95, 0.0, 0.05, 0.0, 0.0, 0.0, 0.04])

          (key: "4Gerbil", value: [40.3, 55.4, 3.0, 0.0, 0.4, 0.9, 0.05])

          (key: "5Fish", value: [7.7, 90.8, 1.2, 0.0, 0.1, 0.2, 0.05])

           

          SAME AFTER 3 times

           

           

          This is absolutely normal. What did you expect ?

           

          Your title says:

          Unexpected for...in array behavior

           

          But that's not in array, that's in dictionary.

          So it is normal, order is not fixed in a dictionary and may change each time you invoke the dictionary.

          • Re: Unexpected for...in array behavior
            eskimo Apple Staff Apple Staff (13,935 points)

            What Claude31 said plus…

            If you want to iterate through the dictionary in the order defined by its keys, here’s a good way to do that:

            for (k, v) in dataTable.sorted(by: { $0.0 < $1.0 }) {
                print(k, v)
            }

            This prints:

            1Cat [99.95, 0.0, 0.05, 0.0, 0.0, 0.0, 0.04]
            2Dog [1.0, 1.0, 0.0, 98.0, 0.0, 0.0, 0.2]
            3Mouse [49.0, 43.2, 3.9, 0.0, 0.2, 3.7, 0.05]
            4Gerbil [40.3, 55.4, 3.0, 0.0, 0.4, 0.9, 0.05]
            5Fish [7.7, 90.8, 1.2, 0.0, 0.1, 0.2, 0.05]

            This approach avoids any redundant key lookups, force unwrapping optionals, and so on.

            Share and Enjoy

            Quinn “The Eskimo!”
            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
            let myEmail = "eskimo" + "1" + "@apple.com"

              • Re: Unexpected for...in array behavior
                waynehend Level 1 Level 1 (5 points)

                "If you want to iterate through the dictionary in the order defined by its keys, here’s a good way to do that:"

                 

                Thanks for that but unfortunately my "real" table isn't sorted in any systematic way.  It may make perfect sense to the user but not to a sort algorithm.  I need to come up with a clever workaround to preserve the order.

                  • Re: Unexpected for...in array behavior
                    Claude31 Level 8 Level 8 (9,205 points)

                    What orginal order do you want to "preserve" ?

                    Probably the best is to cenvert dict to array, then sort on the correct order for future us.

                     

                    Could do this (I assume the original order is the alphabetic of the key):

                     

                    let dataConverted = (dataTable.map() { ($0.key, $0.value)}).sorted(by: { $0.0 <= $1.0 } )
                    print("dataConverted\n", dataConverted)

                     

                    and get

                     

                    dataConverted

                    [("1Cat", [99.95, 0.0, 0.05, 0.0, 0.0, 0.0, 0.04]), ("2Dog", [1.0, 1.0, 0.0, 98.0, 0.0, 0.0, 0.2]), ("3Mouse", [49.0, 43.2, 3.9, 0.0, 0.2, 3.7, 0.05]), ("4Gerbil", [40.3, 55.4, 3.0, 0.0, 0.4, 0.9, 0.05]), ("5Fish", [7.7, 90.8, 1.2, 0.0, 0.1, 0.2, 0.05])]

                     

                    And now, order is preserved

                     

                    print("\n Third form\n")
                    for _ in 1...4 {
                        for i in dataConverted {
                            print(i)
                        }
                        print("\n")
                    }

                    gets:

                    Third form

                     

                    ("1Cat", [99.95, 0.0, 0.05, 0.0, 0.0, 0.0, 0.04])

                    ("2Dog", [1.0, 1.0, 0.0, 98.0, 0.0, 0.0, 0.2])

                    ("3Mouse", [49.0, 43.2, 3.9, 0.0, 0.2, 3.7, 0.05])

                    ("4Gerbil", [40.3, 55.4, 3.0, 0.0, 0.4, 0.9, 0.05])

                    ("5Fish", [7.7, 90.8, 1.2, 0.0, 0.1, 0.2, 0.05])

                     

                     

                    ("1Cat", [99.95, 0.0, 0.05, 0.0, 0.0, 0.0, 0.04])

                    ("2Dog", [1.0, 1.0, 0.0, 98.0, 0.0, 0.0, 0.2])

                    ("3Mouse", [49.0, 43.2, 3.9, 0.0, 0.2, 3.7, 0.05])

                    ("4Gerbil", [40.3, 55.4, 3.0, 0.0, 0.4, 0.9, 0.05])

                    ("5Fish", [7.7, 90.8, 1.2, 0.0, 0.1, 0.2, 0.05])

                     

                     

                    ("1Cat", [99.95, 0.0, 0.05, 0.0, 0.0, 0.0, 0.04])

                    ("2Dog", [1.0, 1.0, 0.0, 98.0, 0.0, 0.0, 0.2])

                    ("3Mouse", [49.0, 43.2, 3.9, 0.0, 0.2, 3.7, 0.05])

                    ("4Gerbil", [40.3, 55.4, 3.0, 0.0, 0.4, 0.9, 0.05])

                    ("5Fish", [7.7, 90.8, 1.2, 0.0, 0.1, 0.2, 0.05])

                     

                     

                    ("1Cat", [99.95, 0.0, 0.05, 0.0, 0.0, 0.0, 0.04])

                    ("2Dog", [1.0, 1.0, 0.0, 98.0, 0.0, 0.0, 0.2])

                    ("3Mouse", [49.0, 43.2, 3.9, 0.0, 0.2, 3.7, 0.05])

                    ("4Gerbil", [40.3, 55.4, 3.0, 0.0, 0.4, 0.9, 0.05])

                    ("5Fish", [7.7, 90.8, 1.2, 0.0, 0.1, 0.2, 0.05])

                      • Re: Unexpected for...in array behavior
                        waynehend Level 1 Level 1 (5 points)

                        "What orginal order do you want to "preserve" ?"

                         

                        Imagine the list above without the leading integers which I used to emphasize the effect.  I'd like the order of the animals to remain unchanged.  They're in no sorted order except for the unknown user preference.

                         

                        I think I'll just put the list of keys into a separate array at the same time the dictionary is initialized.  The user never really sees the dictionary and I can use the list of keys to retain control over the order.

                         

                        I've been reminded by all this that dictionaries are unordered.  I remember reading that but now it has hit home.  Is there a good reason for that?  I mean, it seems like it would always be more useful to have an ordered list than not.