Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does skipWhile behave differently in these examples?

Tags:

swift

rx-swift

In the first example, my terminal outputs

next(1)
next(2)
next(3)
next(4)
next(5)
next(6)
next(7)
next(8)
next(9)
next(10)
completed

In the second example it will output

next(3)
next(6)
next(8)
next(9)
completed

I know the values are different in each, but I would expect the first example to have had filtering applied so it follows the logic within my .skipWhile { $0 % 2 == 0 } block

func skipWhile() {
    let bag = DisposeBag()

    Observable
        .from(Array(1...10))
        .skipWhile { $0 % 2 == 0 }
        .subscribe { print($0) }
        .disposed(by: bag)

    Observable
        .from([2,3,6,8,9])
        .skipWhile { $0 % 2 == 0 }
        .subscribe { print($0) }
        .disposed(by: bag)

}
skipWhile()
like image 721
Tim J Avatar asked Jul 24 '26 12:07

Tim J


1 Answers

skipWhile is not filter. It skips elements at the start of the observable's lifetime while the predicate as true. As soon as an element comes along that no longer satisfies the predicate, it opens the flood gates and let everything else through.

Your first observable says "skip everything until the first odd number". The first element is odd, so nothing is skipped, and that's why you see all array elements being printed.

If you notice in your second observable, you didn't filter out even numbers (because there's an 8). You merely skipped over elements until the first odd number (3), causing the 2 to be skipped.

On a side note

Int.isMultiple(of: ) has been added in Swift 5, and I suggest you use it in cases like this. It just makes it clearer, and side-steps errors caused by misreading == vs !=.

Observable
    .from(Array(1...10))
    .skipWhile { $0.isMultiple(of: 2) }
    .subscribe { print($0) }
    .disposed(by: bag)

You could even name your predicate:

let isEven: (Int) -> Bool = { $0.isMultiple(of: 2) }

Observable
    .from(Array(1...10))
    .skipWhile(isEven)
    .subscribe { print($0) }
    .disposed(by: bag)

Or my favourite, add it as a computed property:

extension BinaryInteger {
    var isEven: Bool { return self.isMultiple(of: 2) }
    var isOdd: Bool { return !self.isEven }
}

Observable
    .from(Array(1...10))
    .skipWhile(\.isEven)
    .subscribe { print($0) }
    .disposed(by: bag)
like image 166
Alexander Avatar answered Jul 27 '26 06:07

Alexander