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