【问题标题】:How to compare multiple keys with distinctUntilKeyChanged?如何将多个键与 distinctUntilKeyChanged 进行比较?
【发布时间】:2017-07-28 01:01:39
【问题描述】:

我还在学习 rxjs,对于如何为运算符 distinctUntilChanged 编写自定义比较函数有点困惑。

我研究过使用 distinctUntilKeyChanged,它适用于单个键...但我有两个键需要比较。

看来我可能需要合并扫描运算符来比较当前发出的值和最后发出的值....?

好的,这是我的代码。我正在从谷歌地图流式传输地图中心的变化。我不需要地图中心 GeoLocation 非常精确,所以我将谷歌地图返回的大部分小数四舍五入。

searchStream$
  .map((value)=>{
  return {
    lat: round(value[1].lat, 1),
    lng: round(value[1].lng, 1)
  }
}).distinctUntilKeyChanged('lat')
  .do((position)=>{console.log(position)})
  .subscribe((position)=>{ this._store.dispatch(new QueryUpdateGeoPositionAPIAction({latitude: position.lat, longitude: position.lng})) });

回到我的问题,我如何比较两个属性(lat & lng)以确保它仅在其中一个值发生变化时才发出值?

感谢您的帮助!

【问题讨论】:

标签: javascript rxjs


【解决方案1】:

我遇到了同样的问题,但文档没有涵盖这种情况。

这将添加.distinctUntilKeysChanged 运算符。只需将任何键传递给它以“监视”

const {
  Observable,
  Subject
} = Rx;

Observable.prototype.distinctUntilKeysChanged = function(...keys) {
  return this.distinctUntilChanged((old, current) =>
    // if no value changed,
    // the array will only have true values,
    // includes(false) will be false,
    // convert to oposite (!),
    // returns true;
    // => true = do nothing

    // if any value changed,
    // the array will include some false,
    // includes(false) will be true,
    // convert to oposite (!),
    // returns false;
    // => false = emit

    !keys
    .map(key => old[key] === current[key]) // converts to array of boolean
    .includes(false) // if any value changed
  );
};

const stream = new Subject();

stream
  .distinctUntilKeysChanged('prop', 'prop2')
  .subscribe(obj => console.log(obj));

// should log
stream.next({
  prop: 42,
  prop2: 54,
});

// should log
stream.next({
  prop: 12346,
  prop2: 54,
});

// shouldn't log because neither prop nor prop2 changed
stream.next({
  prop: 12346,
  prop2: 54,
});

// should log
stream.next({
  prop: 12346,
  prop2: 5454665654645,
});
<script src="https://unpkg.com/@reactivex/rxjs@5.0.3/dist/global/Rx.js"></script>

唯一的缺点是您不能指定自定义比较函数。如果你确实想指定一个,你可以使用它(这更类似于.distinctUntilKeyChanged 的实现,其中第一个参数是键,第二个是比较函数)。请注意,这一个采用一个键数组,其中第一个将键作为单独的参数

const {
  Observable,
  Subject
} = Rx;

Observable.prototype.distinctUntilKeysChanged = function(keys, compare) {
  return this.distinctUntilChanged((old, current) =>
    // if no value changed,
    // the array will only have true values,
    // includes(false) will be false,
    // convert to oposite (!),
    // returns true;
    // => true = do nothing

    // if any value changed,
    // the array will include some false,
    // includes(false) will be true,
    // convert to oposite (!),
    // returns false;
    // => false = emit

    !keys
    .map(key => compare ? compare(old[key], current[key]) : old[key] === current[key]) // converts to array of boolean
    .includes(false) // if any value changed
  );
};

const stream = new Subject();

stream
  .distinctUntilKeysChanged(['prop', 'prop2'])
  .subscribe(obj => console.log(obj));

// should log
stream.next({
  prop: 42,
  prop2: 54,
});

// should log
stream.next({
  prop: 12346,
  prop2: 54,
});

// shouldn't log because neither prop nor prop2 changed
stream.next({
  prop: 12346,
  prop2: 54,
});

// should log
stream.next({
  prop: 12346,
  prop2: 5454665654645,
});
<script src="https://unpkg.com/@reactivex/rxjs@5.0.3/dist/global/Rx.js"></script>

希望你觉得它有用

【讨论】:

    【解决方案2】:

    来自distinct documentation 的 RxJS 部分:

    在 RxJS 中,distinct 运算符有两个可选参数:

    1. 一个函数,它接受源 Observable 发出的项目并返回一个键,当比较两个项目的区别时,将使用该键代替项目本身
    2. 一个接受两个项目(或两个键)并比较它们的区别的函数,如果它们是不同的,则返回false(如果您没有在此处提供自己的函数,则默认为相等函数)

    所以在我看来(没有测试)你可以简单地通过类似的东西

    (a, b) => a.lat === b.lat && a.lon === b.lon 
    

    我不确定 RxJS 约定知道如何传递这个(第二个可选)参数。

    【讨论】:

    • 这是正确的..除了我想将先前发出的值检查为当前值。为此,我需要 distinctUntilChanged 运算符..不仅仅是 distinct 运算符。但是您的代码示例效果很好。谢谢...如果您将答案切换到正确的接线员,我会将其标记为正确。
    • 我不知道distinctUntilChanged 是否有单独的文档。似乎它只是嵌入在distinct 文档页面中。我对 RxJS 没有太多经验,但到目前为止,我发现他们的文档组织相当令人沮丧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-21
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多