-
Notifications
You must be signed in to change notification settings - Fork 7.6k
1.x: distinctUntilChanged with direct value comparator - alternative #4034
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,17 +18,19 @@ | |
import rx.Observable.Operator; | ||
import rx.Subscriber; | ||
import rx.exceptions.Exceptions; | ||
import rx.functions.Func1; | ||
import rx.functions.*; | ||
import rx.internal.util.UtilityFunctions; | ||
|
||
/** | ||
* Returns an Observable that emits all sequentially distinct items emitted by the source. | ||
* @param <T> the value type | ||
* @param <U> the key type | ||
*/ | ||
public final class OperatorDistinctUntilChanged<T, U> implements Operator<T, T> { | ||
public final class OperatorDistinctUntilChanged<T, U> implements Operator<T, T>, Func2<U, U, Boolean> { | ||
final Func1<? super T, ? extends U> keySelector; | ||
|
||
final Func2<? super U, ? super U, Boolean> comparator; | ||
|
||
private static class Holder { | ||
static final OperatorDistinctUntilChanged<?,?> INSTANCE = new OperatorDistinctUntilChanged<Object,Object>(UtilityFunctions.identity()); | ||
} | ||
|
@@ -48,6 +50,19 @@ public static <T> OperatorDistinctUntilChanged<T, T> instance() { | |
|
||
public OperatorDistinctUntilChanged(Func1<? super T, ? extends U> keySelector) { | ||
this.keySelector = keySelector; | ||
this.comparator = this; | ||
|
||
} | ||
|
||
@SuppressWarnings({ "unchecked", "rawtypes" }) | ||
public OperatorDistinctUntilChanged(Func2<? super U, ? super U, Boolean> comparator) { | ||
this.keySelector = (Func1)UtilityFunctions.identity(); | ||
this.comparator = comparator; | ||
} | ||
|
||
@Override | ||
public Boolean call(U t1, U t2) { | ||
return (t1 == t2 || (t1 != null && t1.equals(t2))); | ||
} | ||
|
||
@Override | ||
|
@@ -68,7 +83,16 @@ public void onNext(T t) { | |
previousKey = key; | ||
|
||
if (hasPrevious) { | ||
if (!(currentKey == key || (key != null && key.equals(currentKey)))) { | ||
boolean comparison; | ||
|
||
try { | ||
comparison = comparator.call(currentKey, key); | ||
} catch (Throwable e) { | ||
Exceptions.throwOrReport(e, child, key); | ||
return; | ||
} | ||
|
||
if (!comparison) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a subtle NPE potential here. Not sure if you want to explicitly guard against it from a misbehaving There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! I'll change the comparison to be primitive boolean to trigger NPE inside the try-block if necessary. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
child.onNext(t); | ||
} else { | ||
request(1); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cute trick