swift - The elegant solution for function that gives everytime called different element of array(ordered and starting from new when all returned)? -
i newbie , wonder elegant/grown-up solution code be.
i thankful terms can related this, seems common task.
the "1,2,3" are placeholders solution shouldn't rely on them being numbers
var myvalues = [1,2,3] //function, returns 1 element array, in order, , starts //from beginning when elements been returned once,twice etc. func popper() -> int { let returnvalue = myvalues.poplast() myvalues.insert(returnvalue!, at: 0) return returnvalue! popper() = 3 popper() = 2 popper() = 1 popper() = 3 ... it not important starts last, 1231231... great!
edit: maybe more descriptive example:
i having 1 clickbutton changes backgroundcolor array of ["red","green","blue"]. when clicking multiple times background turns red, turns green, turns blue, turns red ... not random , not ending.
this process of "popping" iteration... of custom sequence. appropriate way of representing in swift type (struct/class) implements iteratorprotocol. called mine sequencerepeatingiterator. iterators used directly. rather, they're provided type conforms sequence. called mine sequencerepeater
the sequence protocol requires conforming type provide function, makeiterator(), returns iterator (sequencerepeatingiterator in case). doing this, instantly gain of functionality of sequences. iterability, map/filter/reduce, prefix, suffix, etc.
the iteratorprotocol requires type provide function, next(), yields returns element?. return value optional, nil used represent end of sequence.
here how implement these:
struct sequencerepeater<c: collection>: sequence { let elements: c init(repeatingelementsof elements: c) { self.elements = elements } func makeiterator() -> sequencerepeatingiterator<c> { return sequencerepeatingiterator(repeatingelementsof: elements) } } struct sequencerepeatingiterator<c: collection>: iteratorprotocol { let elements: c var elementiterator: c.iterator init(repeatingelementsof elements: c) { self.elements = elements self.elementiterator = elements.makeiterator() } mutating func next() -> c.iterator.element? { guard !elements.isempty else { return nil } if let nextelement = elementiterator.next() { return nextelement } else { self.elementiterator = elements.makeiterator() return self.elementiterator.next() } } } let s1 = sequencerepeater(repeatingelementsof: [1, 2, 3]) //works arrays of numbers, expect. var i1 = s1.makeiterator() print(i1.next() any) //taking 1 element @ time, manually print(i1.next() any) print(i1.next() any) print(i1.next() any) print(i1.next() any) print(i1.next() any) print(i1.next() any) let s2 = sequencerepeater(repeatingelementsof: 2...5) // works collect. ranges work! print(array(s2.prefix(10))) //taking first 10 elements let s3 = sequencerepeater(repeatingelementsof: ["a", "b", "c"]) // arrays of strings work, too! s3.prefix(10).map{ "you can map on me! \($0)" }.foreach{ print($0) } here's shorter, alternate implementation shows how sequence(state:next:) can used achieve similar thing.
func makecollectionrepeater<c: collection>(for c: c) -> anysequence<c.iterator.element> { return anysequence( sequence(state: (elements: c, elementiterator: c.makeiterator()), next: { state in guard !state.elements.isempty else { return nil } if let nextelement = state.elementiterator.next() { return nextelement } else { state.elementiterator = state.elements.makeiterator() return state.elementiterator.next() } }) ) } let repeater = makecollectionrepeater(for: [1, 2, 3]) print(array(repeater.prefix(10)))
Comments
Post a Comment