The Elegant Solution for Function That Gives Everytime Called Different Element of Array(Ordered and Starting from New When All Returned)

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



Leave a reply



Submit