[swift-evolution] [swift-users] Multi dimensional - iterator, Iterator2D, Iterator3D

Ted F.A. van Gaalen tedvgiosdev at gmail.com
Tue Aug 2 10:02:13 CDT 2016


> On 01.08.2016, at 17:45, Saagar Jha <saagar at saagarjha.com> wrote:
> 
> With your method, don't you need to write a new method for every dimension?
Hi Saagar,

Yes, one could solve this by writing a function
that propagates though all iteration levels, possibly recursively,
I might try to implement that.
left “as an exercise to the astute reader” :o)   

Kind regards
Ted


> On Mon, Aug 1, 2016 at 08:43 Ted F.A. van Gaalen via swift-users <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
> Hi Erica
> 
> That would also be a workable solution, but imho still too tedious as 
> it has been so for many years, with nested iteration statements…
> many times this is for;; for;; for tables and for;;for;;for;; for 3D structuring.
>   
> 
> Swift offers nice features (like protocols and generics as you know) to improve this. 
> 
> - I no longer have to nest for;; s  so, Now I rather do this:  
> Your example can already be coded like this:
> 
>    iterate2D( 1, 2, { $0 < 64 } ,
>               1, 2, { $0 < 64 } ,
>                   {outerIndex,innerIndex in
>                       print (outerIndex,InnerIndex)
>                       
>                       return true // Obligatory. return “false" to break
>                    }  )
> 
> With no chances in Swift, this already works like a charm!
> Imho much more readable and compact,
> 
> Uses - AFAICS from a programmers’s perspective - no 
> underlying deep collection based coding with Sequence. etc.
> 
> I am already deploying it in my own apps e.g. l
> (replaced for;; for;; for;; in the app)  
> 
> By using this new iterator…() functions my coding gets leaner 
> and errors are easier to spot. 
> 
> Actual working code with Swift 2.x here: 
> 
>   func generateTiles()
>   {
>         let w:      Float =   20  // tile size
>         let h:      Float =    5
>         let l:      Float =    5
>         
>         let xstart: Float = -120
>         let ystart: Float =  -60
>         let zstart: Float =  -10
>         
>         let xend: Float = 120
>         let yend: Float =  60
>         let zend: Float =  10
>         
>         let tolerance:Float = 0.001 // float drift compensation
>         
>         iterate3D( xstart, w * 1.2, { $0 < xend + tolerance } ,
>                    ystart, h * 1.2, { $0 < yend + tolerance } ,
>                    zstart, l * 1.2, { $0 < zend + tolerance } ,
>                    {
>                     x,y,z in
>                     self.addTile(x,y,z,  
>                                  w,h,l)
>                     return true
>                    }  )
>     }
> 
> This generates a group of blocks or tiles in my Apple TV app (under construction)
> like the one you can see  in the image “Cloinckz” on my website www.tedvg.com <http://www.tedvg.com/>.
> 
> I also prefer the one dimensional iterate(..  too above the for;; or stride()
> 
> One could extend these iterator…() functions by adding closures for pre and post iteration handling,
> like for printing headers and footers before and/or after a complete [inner] iteration.
> 
> Note that breaking with *return false* -which is equivalent to the “break” stmt in
> a classical for;; -  does not only leave a nested iteration, but also the outer ones.
> (maybe a TODO to make individual level- break possible)  As it is now, If one 
> wants to break at the deep iteration level, then one should nest this using 1D iterators.
> 
> 
> Anyway, this is just a thought starting to think about multi-dimensional iterators,
> and other (encapsulation?) of multi dimensional data as well.
> In any case for 2D because table data is used very frequently in many apps. as
> most data are in tables.
> 
> You won’t believe this :o) but in a sense I might not make so much fuzz anymore
> to keep the for;;  as this proves to me that I can solve things much better that I thought.
> So, I have to rethink this.
> 
> Kind Regards
> Ted  
> www.ravelnotes.com <http://www.ravelnotes.com/>
> 
>  
> 
> 
> 
> 
> 
>> On 31.07.2016, at 18:33, Erica Sadun <erica at ericasadun.com <mailto:erica at ericasadun.com>> wrote:
>> 
>> I'm replying on Swift-Users and bcc'ing in Swift-Evolution to comply with the core team's request to focus SE on the current mission statement. 
>> 
>> At some point soon, Russ Bishop's PR https://github.com/apple/swift/pull/3600 <https://github.com/apple/swift/pull/3600> will be incorporated into Swift 3. This PR adds `prefix(while:)` and `drop(while:)` to finish implementing SE-0045.  Once that's done, you can  combine `sequence(first:, next:)` and `prefix(while:)` to into a single function `sequence(first:, next:, while:)` like this:
>> 
>> public func sequence<T>(first: T, next: (T) -> T?, while test: (T) -> Bool) -> UnfoldSequence<T, UnfoldSequence<T, (T?, Bool)>> {
>>     return sequence(first: first, next: next).prefix(while: test)
>> }
>> 
>> The combined sequence/prefix call allows you to create loops like this:
>> 
>> for outerIndex in sequence(first: 1, next: { $0 * 2 }, while: { $0 <= 64 }) {
>>     for innerIndex in sequence(first: 1, next: { $0 * 2 }, while: { $0 <= 64 }) {
>>         print(outerIndex, innerIndex)
>>     }
>> }
>> 
>> These loops can be nested. break and continue work.  You can use tuples for multiple arguments. While I'd like to see a combined form adopted into Swift 4b (the deferred "sugar"), it isn't a high priority.
>> 
>> -- E
>> 
>> 
>>> On Jul 31, 2016, at 7:18 AM, Ted F.A. van Gaalen via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>> 
>>>> On 31.07.2016, at 04:28, jaden.geller at gmail.com <mailto:jaden.geller at gmail.com> wrote:
>>>> 
>>>> What benefit do Iterator2D and Iterator3D provide that nesting does not?
>>> Hi Jaden,
>>> well, simply because of hiding/enclosing repetitive functionality
>>> like with every other programming element is convenient,
>>> prevents errors and from writing the same over and over again.
>>> That is why there are functions.
>>> but you already know that, of course.
>>> Kind Regards
>>> TedvG
>>> 
>>>> 
>>>> On Jul 30, 2016, at 1:48 PM, Ted F.A. van Gaalen via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>> 
>>>>> Hi Chris,
>>>>> 
>>>>> thanks for the tip about Hirundo app!
>>>>> 
>>>>> A positive side-effect of removing the classical for;; loop
>>>>>  (yes, it’s me saying this :o)  is that it forces me to find
>>>>> a good and generic equivalent for it, 
>>>>> making the conversion of my for;;s to 3.0 easier.
>>>>> which is *not* based on collections or sequences and
>>>>> does not rely on deeper calls to Sequence etc.
>>>>> 
>>>>> so, I’ve made the functions [iterator, iterator2D, iterator3D]  (hereunder)
>>>>> wich btw clearly demonstrate the power and flexibility of Swift. 
>>>>> 
>>>>> Very straightforward, and efficient (i assume) just like the classical for;; loop.  
>>>>> It works quite well in my sources.
>>>>> 
>>>>> As a spin-off,  I’ve extended these to iterators for matrices 2D and cubes? 3D...
>>>>> 
>>>>> Question: 
>>>>> Perhaps implementing “multi dimensional iterator functions
>>>>> in Swift might  be a good idea. so that is no longer necessary to nest/nest/nest iterators. 
>>>>> 
>>>>> Met vriendelijke groeten, sorry for my “intensity” in discussing the classical for;; 
>>>>> I'll have to rethink this for;; again..  
>>>>> Thanks, Ted.
>>>>> 
>>>>> Any remarks ( all ), suggestions about the code hereunder:              ? 
>>>>> 
>>>>> protocol NumericType
>>>>> {
>>>>>     func +(lhs: Self, rhs: Self) -> Self
>>>>>     func -(lhs: Self, rhs: Self) -> Self
>>>>>     func *(lhs: Self, rhs: Self) -> Self
>>>>>     func /(lhs: Self, rhs: Self) -> Self
>>>>>     func %(lhs: Self, rhs: Self) -> Self
>>>>> }
>>>>> 
>>>>> extension Double : NumericType { }
>>>>> extension Float  : NumericType { }
>>>>> extension CGFloat: NumericType { }
>>>>> extension Int    : NumericType { }
>>>>> extension Int8   : NumericType { }
>>>>> extension Int16  : NumericType { }
>>>>> extension Int32  : NumericType { }
>>>>> extension Int64  : NumericType { }
>>>>> extension UInt   : NumericType { }
>>>>> extension UInt8  : NumericType { }
>>>>> extension UInt16 : NumericType { }
>>>>> extension UInt32 : NumericType { }
>>>>> extension UInt64 : NumericType { }
>>>>> 
>>>>> 
>>>>> /// Simple iterator with generic parameters, with just a few lines of code.
>>>>> /// for most numeric types (see above)
>>>>> /// Usage Example:
>>>>> ///
>>>>> ///   iterate(xmax, { $0 > xmin}, -xstep,
>>>>> ///    {x in
>>>>> ///        print("x = \(x)")
>>>>> ///        return true  // returning false acts like a break
>>>>> ///     } )
>>>>> ///
>>>>> ///  -Parameter vstart: Initial value
>>>>> ///  -Parameter step:    The iteration stepping value.
>>>>> ///  -Parameter test:    A block with iteration test. e.g. {$0 > 10}
>>>>> ///
>>>>> ///  -Parameter block:   A block to be executed with each step.
>>>>> ///       The block must include a return true (acts like "continue")
>>>>> ///                                   or false (acts like "break")
>>>>> ///  -Please Note: 
>>>>> ///  There is minor precision loss ca: 1/1000 ... 1/500 
>>>>> ///  when iterating with floating point numbers.
>>>>> ///  However, in most cases this can be safely ignored.
>>>>> ///  made by ted van gaalen.
>>>>> 
>>>>> 
>>>>> func iterate<T:NumericType> (
>>>>>                     vstart:  T,
>>>>>                    _ vstep:  T,
>>>>>                    _  test: (T) -> Bool,
>>>>>                    _ block: (T) -> Bool )
>>>>> {
>>>>>     var current = vstart
>>>>>     
>>>>>     while test(current) && block(current)
>>>>>     {
>>>>>         current = current + vstep
>>>>>     }
>>>>> }
>>>>> 
>>>>> 
>>>>> /// X,Y 2D matrix (table) iterator with generic parameters
>>>>> func iterate2D<T:NumericType> (
>>>>>      xstart:  T,  _ xstep: T, _ xtest: (T) -> Bool,
>>>>>    _ ystart:  T,  _ ystep: T, _ ytest: (T) -> Bool,
>>>>>    _ block: (T,T) -> Bool )
>>>>> {
>>>>>     var xcurrent = xstart
>>>>>     var ycurrent = ystart
>>>>>     
>>>>>     var dontStop = true
>>>>>     
>>>>>     while xtest(xcurrent) && dontStop
>>>>>     {
>>>>>         ycurrent = ystart
>>>>>         while ytest(ycurrent) && dontStop
>>>>>         {
>>>>>             dontStop = block(xcurrent, ycurrent)
>>>>>             ycurrent = ycurrent + ystep
>>>>>         }
>>>>>         xcurrent = xcurrent + xstep
>>>>>     }
>>>>> }
>>>>> 
>>>>> 
>>>>> /// X,Y,Z 3D (cubic) iterator with generic parameters:
>>>>> 
>>>>> func iterate3D<T:NumericType> (
>>>>>     xstart:  T,  _ xstep: T, _ xtest: (T) -> Bool,
>>>>>   _ ystart:  T,  _ ystep: T, _ ytest: (T) -> Bool,
>>>>>   _ zstart:  T,  _ zstep: T, _ ztest: (T) -> Bool,
>>>>>       _ block: (T,T,T) -> Bool )
>>>>> {
>>>>>     var xcurrent = xstart
>>>>>     var ycurrent = ystart
>>>>>     var zcurrent = zstart
>>>>>     
>>>>>     var dontStop = true
>>>>>     
>>>>>     while xtest(xcurrent) && dontStop
>>>>>     {
>>>>>         ycurrent = ystart
>>>>>         while ytest(ycurrent) && dontStop
>>>>>         {
>>>>>             zcurrent = zstart
>>>>>             while ztest(zcurrent) && dontStop
>>>>>             {
>>>>>                 dontStop = block(xcurrent, ycurrent, zcurrent)
>>>>>                 zcurrent = zcurrent + zstep
>>>>>             }
>>>>>             ycurrent = ycurrent + ystep
>>>>>         }
>>>>>         xcurrent = xcurrent + xstep
>>>>>     }
>>>>> }
>>>>> 
>>>>> 
>>>>> func testIterator()
>>>>> {
>>>>>     iterate(0.0, 0.5, {$0 < 1000.00000} ,
>>>>>             { value in
>>>>>                 print("Value = \(value) ")
>>>>>                 return true
>>>>>     } )
>>>>> 
>>>>>     let startv: CGFloat = -20.0
>>>>>     let stepv: CGFloat =   0.5
>>>>>     
>>>>>     iterate(startv, stepv, {$0 < 1000.00000} ,
>>>>>             { val in
>>>>>                 print("R = \(val)")
>>>>>                 return true
>>>>>     } )
>>>>> 
>>>>>     let tolerance = 0.01 // boundary tolerance for floating point type
>>>>>     
>>>>>     iterate2D( 0.0, 10.0, { $0 < 100.0 + tolerance } ,
>>>>>                0.0,  5.0, { $0 <  50.0 + tolerance } ,
>>>>>                {x,y in
>>>>>                 print("x = \(x) y = \(y)")
>>>>>                 return true  // false from block stops iterating ( like break)
>>>>>                 } )
>>>>> 
>>>>>     iterate3D( 0.0,  10.0, { $0 <   30.0 } ,  // x
>>>>>                0.0,   5.0, { $0 <   20.0 } ,  // y
>>>>>                10.0, -5.0, { $0 >  -10.0 } ,  // z
>>>>>                {x,y,z in
>>>>>                     print("x = \(x) y = \(y) z = \(z)")
>>>>>                     if z < 0.0
>>>>>                     {
>>>>>                         print ( "** z value \(z) is below zero! **" )
>>>>>                         
>>>>>                         return false  // (acts as break in for;;)
>>>>>                     }
>>>>>                     return true  // return stmt is obligatory (continue)
>>>>>                } )
>>>>> }
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 
> 
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org <mailto:swift-users at swift.org>
> https://lists.swift.org/mailman/listinfo/swift-users <https://lists.swift.org/mailman/listinfo/swift-users>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160802/bc15f525/attachment-0001.html>


More information about the swift-evolution mailing list