The elegant solution for function that gives everytime called different element of array(ordered and starting from new when all returned)?
Update: The Swift Algorithms package incorporates exactly this algorithm, under the name Cycle<T>
. See https://github.com/apple/swift-algorithms/blob/main/Guides/Cycle.md
This process of "popping" is actually iteration... of a custom sequence.
The appropriate way of representing this in Swift is as a type (struct
/class
) that implements the IteratorProtocol
. I called mine CycleIterator
. Iterators are rarely used directly. Rather, they're usually provided by a type that conforms to Sequence
. I called mine CycleSequence
The Sequence
protocol simply requires the conforming type to provide a function, makeIterator()
, which returns an iterator (CycleIterator
in my case). Simply by doing this, you instantly gain all of functionality of sequences. Iterability, map
/filter
/reduce
, prefix
, suffix
, etc.
The IteratorProtocol
simply requires that this type provide a function, next()
, which yields returns a Element?
. The return value is optional, as nil
is used to represent the end of a sequence.
Here is how I would implement these:
public struct CycleSequence<C: Collection>: Sequence {
public let cycledElements: C
public init(cycling cycledElements: C) {
self.cycledElements = cycledElements
}
public func makeIterator() -> CycleIterator<C> {
return CycleIterator(cycling: cycledElements)
}
}
public struct CycleIterator<C: Collection>: IteratorProtocol {
public let cycledElements: C
public private(set) var cycledElementIterator: C.Iterator
public init(cycling cycledElements: C) {
self.cycledElements = cycledElements
self.cycledElementIterator = cycledElements.makeIterator()
}
public mutating func next() -> C.Iterator.Element? {
if let next = cycledElementIterator.next() {
return next
} else {
self.cycledElementIterator = cycledElements.makeIterator() // Cycle back again
return cycledElementIterator.next()
}
}
}
let s1 = CycleSequence(cycling: [1, 2, 3]) // Works with arrays of numbers, as you would expect.
// Taking one element at a time, manually
var i1 = s1.makeIterator()
print(i1.next() as Any) // => Optional(1)
print(i1.next() as Any) // => Optional(2)
print(i1.next() as Any) // => Optional(3)
print(i1.next() as Any) // => Optional(1)
print(i1.next() as Any) // => Optional(2)
print(i1.next() as Any) // => Optional(3)
print(i1.next() as Any) // => Optional(1)
let s2 = CycleSequence(cycling: 2...5) // Works with any Collection. Ranges work!
// Taking the first 10 elements
print(Array(s2.prefix(10))) // => [2, 3, 4, 5, 2, 3, 4, 5, 2, 3]
let s3 = CycleSequence(cycling: "abc") // Strings are Collections, so those work, too!
s3.prefix(10).map{ "you can even map over me! \($0)" }.forEach{ print($0) }
print(Array(CycleSequence(cycling: [true, false]).prefix(7))) // => [true, false, true, false, true, false, true]
print(Array(CycleSequence(cycling: 1...3).prefix(7))) // => [1, 2, 3, 1, 2, 3, 1]
print(Array(CycleSequence(cycling: "ABC").prefix(7))) // => ["A", "B", "C", "A", "B", "C", "A"]
print(Array(CycleSequence(cycling: EmptyCollection<Int>()).prefix(7))) // => []
print(Array(zip(1...10, CycleSequence(cycling: "ABC")))) // => [(1, "A"), (2, "B"), (3, "C"), (4, "A"), (5, "B"), (6, "C"), (7, "A"), (8, "B"), (9, "C"), (10, "A")]
Here's a shorter, alternate implementation that shows how sequence(state:next:)
can be used to achieve a similar thing.
func makeCycleSequence<C: Collection>(for c: C) -> AnySequence<C.Iterator.Element> {
return AnySequence(
sequence(state: (elements: c, elementIterator: c.makeIterator()), next: { state in
if let nextElement = state.elementIterator.next() {
return nextElement
}
else {
state.elementIterator = state.elements.makeIterator()
return state.elementIterator.next()
}
})
)
}
let repeater = makeCycleSequence(for: [1, 2, 3])
print(Array(repeater.prefix(10)))
Cycle iterator in Swift
What's wrong with manually implementing a Sequence
backed by some array access modulo its length? With a bit of care your index need never overflow, and you can cycle on for as long as you like.
Note that the API docs warning reads more like a friendly reminder that re-use isn't a mandatory part of the Sequence
interface contract. But that doesn't exclude your particular implementation from being reusable between multiple loops.
Loop over a small array repeatedly to get a larger number of items
The modulo operator %
is going to be your friend here.
I don't have a compiler in front of me and always mess up the range syntax but the below should illustrate the idea…
for i in 0..<100 {
let theItem = array[i % array.count]
}
Shift elements in array by index
You can use ranged subscripting and concatenate the results. This will give you what you're looking for, with names similar to the standard library:
extension Array {
func shiftRight(var amount: Int = 1) -> [Element] {
guard count > 0 else { return self }
assert(-count...count ~= amount, "Shift amount out of bounds")
if amount < 0 { amount += count } // this needs to be >= 0
return Array(self[amount ..< count] + self[0 ..< amount])
}
mutating func shiftRightInPlace(amount: Int = 1) {
self = shiftRight(amount)
}
}
Array(1...10).shiftRight()
// [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
Array(1...10).shiftRight(7)
// [8, 9, 10, 1, 2, 3, 4, 5, 6, 7]
Instead of subscripting, you could also return Array(suffix(count - amount) + prefix(amount))
from shiftRight()
.
How to zip observables with repeating the shorter sequence
When in doubt, you can always make your own operator:
extension ObservableType {
public static func zipRepeat<A, B>(_ a: Observable<A>, _ b: Observable<B>) -> Observable<(A, B)> {
return Observable.create { observer in
var aa: [A] = []
var aComplete = false
var bb: [B] = []
var bComplete = false
let lock = NSRecursiveLock()
let disposableA = a.subscribe { event in
lock.lock(); defer { lock.unlock() }
switch event {
case .next(let ae):
aa.append(ae)
if bComplete {
observer.onNext((ae, bb[(aa.count - 1) % bb.count]))
}
else if bb.count == aa.count {
observer.onNext((aa.last!, bb.last!))
}
case .error(let error):
observer.onError(error)
case .completed:
aComplete = true
if bComplete {
observer.onCompleted()
}
}
}
let disposableB = b.subscribe { event in
lock.lock(); defer { lock.unlock() }
switch event {
case .next(let be):
bb.append(be)
if aComplete {
observer.onNext((aa[(bb.count - 1) % aa.count], be))
}
else if bb.count == aa.count {
observer.onNext((aa.last!, bb.last!))
}
case .error(let error):
observer.onError(error)
case .completed:
bComplete = true
if aComplete {
observer.onCompleted()
}
}
}
return Disposables.create(disposableA, disposableB)
}
}
}
And a test showing the functionality:
class RxSandboxTests: XCTestCase {
func testLongA() {
let scheduler = TestScheduler(initialClock: 0)
let a = scheduler.createColdObservable([.next(10, "a"), .next(20, "b"), .next(30, "c"), .next(40, "d"), .next(50, "e"), .next(60, "f"), .completed(60)])
let b = scheduler.createColdObservable([.next(10, 1), .next(20, 2), .next(30, 3), .completed(30)])
let bResults = scheduler.start {
Observable<(String, Int)>.zipRepeat(a.asObservable(), b.asObservable()).map { $0.1 }
}
XCTAssertEqual(bResults.events, [.next(210, 1), .next(220, 2), .next(230, 3), .next(240, 1), .next(250, 2), .next(260, 3), .completed(260)])
}
func testLongB() {
let scheduler = TestScheduler(initialClock: 0)
let a = scheduler.createColdObservable([.next(10, "a"), .next(20, "b"), .next(30, "c"), .completed(30)])
let b = scheduler.createColdObservable([.next(10, 1), .next(20, 2), .next(30, 3), .next(40, 4), .next(50, 5), .next(60, 6), .completed(60)])
let aResults = scheduler.start {
Observable<(String, Int)>.zipRepeat(a.asObservable(), b.asObservable()).map { $0.0 }
}
XCTAssertEqual(aResults.events, [.next(210, "a"), .next(220, "b"), .next(230, "c"), .next(240, "a"), .next(250, "b"), .next(260, "c"), .completed(260)])
}
}
Permutations in JavaScript?
If you notice, the code actually splits the chars into an array prior to do any permutation, so you simply remove the join and split operation
var permArr = [], usedChars = [];
function permute(input) { var i, ch; for (i = 0; i < input.length; i++) { ch = input.splice(i, 1)[0]; usedChars.push(ch); if (input.length == 0) { permArr.push(usedChars.slice()); } permute(input); input.splice(i, 0, ch); usedChars.pop(); } return permArr};
document.write(JSON.stringify(permute([5, 3, 7, 1])));
How can I find matching values in two arrays?
Naturally, my approach was to loop through the first array once and check the index of each value in the second array. If the index is > -1
, then push
it onto the returned array.
Array.prototype.diff = function(arr2) {
var ret = [];
for(var i in this) {
if(arr2.indexOf(this[i]) > -1){
ret.push(this[i]);
}
}
return ret;
};
My solution doesn't use two loops like others do so it may run a bit faster. If you want to avoid using for..in
, you can sort both arrays first to reindex all their values:
Array.prototype.diff = function(arr2) {
var ret = [];
this.sort();
arr2.sort();
for(var i = 0; i < this.length; i += 1) {
if(arr2.indexOf(this[i]) > -1){
ret.push(this[i]);
}
}
return ret;
};
Usage would look like:
var array1 = ["cat", "sum","fun", "run", "hut"];
var array2 = ["bat", "cat","dog","sun", "hut", "gut"];
console.log(array1.diff(array2));
If you have an issue/problem with extending the Array prototype, you could easily change this to a function.
var diff = function(arr, arr2) {
And you'd change anywhere where the func originally said this
to arr2
.
Related Topics
Troubles With Starting Value Using Uislider
Swift 2 to 3 Migration for Prepareforsegue
How to Set the Blurradius of Uiblureffectstyle.Light
A Swift Protocol Requirement That Can Only Be Satisfied by Using a Final Class
Is There a Prefix Header (Or Something with This Functionality) in Swift
Checking for Nil Value in Swift Dictionary Extension
How to Use Array.Filter to Filter a Class Object Based on a Property
How to Go Back to the Initial View Controller in Swift
Is Force Cast Really Bad and Should Always Avoid It
Swift Spritekit Adding Button Programmatically
May I Create an Instance of a Structure Using a Simple Int
Swift 2/iOS 9 - Libz.Dylib Not Found