rxjs中的值交换有这么复杂吗?

rxjs中的值交换有这么复杂吗?,rxjs,Rxjs,在Javascript中,切换值非常容易: 我知道,可观测值通常不打算以这种方式使用,但使用它们的索引交换两个元素真的有那么困难吗: // assumption that index < newIndex var values = [...]; var values$ = Rx.Observable.from(values); var swapValues$ = values$ .take(index - 1) .concat( values$

在Javascript中,切换值非常容易:

我知道,
可观测值
通常不打算以这种方式使用,但使用它们的索引交换两个元素真的有那么困难吗:

// assumption that index < newIndex
var values = [...];
var values$ = Rx.Observable.from(values);
var swapValues$ = values$
    .take(index - 1)
    .concat(
      values$
        .take(newIndex - 1)
        .skip(index + 1)
        .startWith(values[newIndex]), 
      values$
        .skip(newIndex + 1)
        .startWith(values[index])
    )
//假设索引

我缺少了一种更简单的方法吗?

在一个数组中交换两个值而不作为某个更大操作的一部分是非常罕见的,例如,排序将交换数组中的值

然而,如果你真的想,你可以做一些像

function swap<T>(input: Observable<T[]>, indexOne: number, indexTwo: number): Observable<T[]> {
  return input.map(arr => {
    arr[indexOne] = arr.splice(indexTwo, 1, arr[indexOne])[0];
    return arr;
  });
}
函数交换(输入:可观察,索引:编号,索引:编号):可观察{
返回input.map(arr=>{
arr[indexOne]=arr.splice(indexTwo,1,arr[indexOne])[0];
返回arr;
});
}
然而,我的猜测是,无论你在做什么更大的操作,都有更好的方法来处理,而不必进行单独的互换。例如,如果要进行排序,就不会将其实现为对可观察对象的一系列交换。你可以这样做:

function sort<T>(input: Observable<T[]>): Observable<T[]> {
  return input.map(arr => {
    arr.sort();
    return arr;
  });
}
函数排序(输入:可观察):可观察{
返回input.map(arr=>{
arr.sort();
返回arr;
});
}

交换仍然会发生,但它们发生在map函数中,您处理的是数组,而不是可观察的。您别无选择,只能创建一个状态机来延迟发送较早的(左手)值。Rx的设计在很多方面都是为了避免状态及其不可变的观察值,这就是为什么交换从根本上说是非常尴尬的。出于同样的原因,
Subject
,这个可变的对应物,也适合这个工作

至少有一个状态变量:swap中的lefthand元素。您可以提供谓词来标识左侧和右侧的值。在您的特定示例中,我们需要一个计数器来进行索引比较,我将在
reduce
中匿名:

(function() {
  let lefthand = null;
  const subj = new Rx.Subject();
  const d = values$.reduce((counter, value) => {
    if(counter === index) lefthand = value;
    else {
      subj.onNext(value);
      if(counter === newIndex) subj.onNext(lefthand);
    }
    return counter + 1;
  }, 0)
                   .catch(subj.onError)
                   .finally(subj.onComplete);
  return subj.asObservable();
})();


另一方面,我想确保您的示例只是一个玩具程序,因为依赖
数组而不首先交换数组上的值似乎很愚蠢。否则,您将不得不使用四个可观察链:一个用于[0,index),一个用于(index,newIndex),一个用于发出index,最后一个用于(newIndex,])。虽然使用
主题似乎同样冗长,但在我看来,它更好地表达了您的意图。

您的解决方案仅适用于即时可观测。在可观测的一般情况下,随着时间的推移,项目会发出,将可观测项串联起来将不起作用

假设可以观测到的源是

var值$=Observable.interval(1000);/…0..1..2..3..4..5。。
假设我们想交换索引2和索引4中的项目,其中预期结果是..0..1..4.3..2.5

var指数=2;
var-newIndex=4;
除了在index和newIndex(两者都包括)之间缓冲所有项之外,别无选择。然后,我们可以交换这些值,并将它们作为单独的项发送回

为此,我们需要对index和newIndex之间的序列进行特殊处理

var windowFrames$=values$.filter((|,i)=>i==index-1 | | i==newIndex);/“filter”谓词第二个参数是已发出项的索引
2个索引作为窗口信号:索引-1和新索引

var swapvalue$=值$
.window(windowFrames$)
.switchMap((帧$,i)=>
i==1?//索引-1和newIndex之间的帧索引
frame$.toArray().flatMap(x=>Observable.from(swapFirstWithLast(x)):
帧$);
我们将源可观测值$分为三帧,每帧开始一个可观测值,并在下一帧开始时完成(行为)。对于第二帧(其中i==1),我们将序列缓冲到一个数组中,交换该帧的第一个和最后一个值,然后将所有值作为分离的值发射回来(使用)


一个工作示例-

值可能在不同的时间到达,因此要更改到达顺序,除了缓存第一个值并仅在第二个值到达后发出外,没有其他方法。