Rxjsにはたくさんのコードがあり、
return Observable.from(input_array)
.concatMap((item)=>{
//this part emits an Observable.of<string> for each item in the input_array
})
.scan((output_array:string[],each_item_output_array:string)=>{
return output_array.Push(each_item_output_array) ;
});
しかし、明らかにこれは間違っています。スキャンによってconcatMap内のコードが壊れるので、監視可能なfrom
演算子で各項目の出力配列を収集する方法を知りたいですか?
scan
の呼び出しで、アキュムレータのシードを指定していません。その場合、最初の値がシードとして使用されます。例えば:
Rx.Observable
.from(["a", "b", "c"])
.scan((acc, value) => acc + value)
.subscribe(value => console.log(value));
<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>
スニペットでは、最初の値は配列ではないため、Push
を呼び出すことはできません。値を配列に累積するには、次のように配列シードを指定できます。
Rx.Observable
.from(["a", "b", "c"])
.concatMap(value => Rx.Observable.of(value))
.scan((acc, value) => {
acc.Push(value);
return acc;
}, []) // Note that an empty array is use as the seed
.subscribe(value => console.log(JSON.stringify(value)));
<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>
ただし、一部のユースケースでは、配列を変更しない方が望ましい場合があります。
Rx.Observable
.from(["a", "b", "c"])
.concatMap(value => Rx.Observable.of(value))
.scan((acc, value) => [...acc, value], [])
.subscribe(value => console.log(JSON.stringify(value)));
<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>
scan
は、受け取る値ごとに配列を生成することに注意してください。オブザーバブルが完了したときに単一の配列のみを出力したい場合は、代わりにtoArray
演算子を使用できます。
Rx.Observable
.from(["a", "b", "c"])
.concatMap(value => Rx.Observable.of(value))
.toArray()
.subscribe(value => console.log(JSON.stringify(value)));
<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>
別のオプションはbufferCount(count)
です。入力配列の長さがわかっている場合、その数の項目を含む単一の出力を取得できます。 scan
の使用方法を覚えておかなければならないよりも、構文が簡潔です。
注:サイズがわからない場合(例ではわかっていますが)、count
は最大値を表しますが、これにはリソースの制約がある可能性があるため、99999にしないでください。
_ const array = source$.pipe(bufferCount(10));
_
私の場合、実行中の「操作」のリストがあり、ステップの総数が事前にわかっていたので、bufferCount
は非常にうまく機能しました。ただし、エラー条件を慎重に検討してください。
_ // one approach to handling errors that still returns an output array
// only use this if a single failure shouldn't stop the collection
const array = source$.pipe(
map((result) => ({ hasError: false, result: result }),
catchError((err) => ({ hasError: true, error: err }),
bufferCount(10));
_
エラーの処理方法の決定は、実際のオブザーバブルが何であるかによって大きく異なりますが、ここでのポイントは、bufferCount()
をオプションとして表示することです。
(利用可能な他のbuffer
操作もあります)
このコードに注意してください:
const obs = Rx.Observable
.from(["a", "b", "c"])
.concatMap(value => Rx.Observable.of(value))
.scan((acc, value) => {
acc.Push(value);
return acc;
}, []);
obs.subscribe(value => console.log(JSON.stringify(value)));
obs.subscribe(value => console.log(JSON.stringify(value)));
結果は少し予想外になります:
["a"]
["a","b"]
["a","b","c"]
["a","b","c","a"]
["a","b","c","a","b"]
["a","b","c","a","b","c"]
「acc」変数は参照オブジェクトであり、各サブスクライバーはストリームデータを取得し、同じオブジェクトにデータを再度追加します。これを回避するための多くの解決策になる可能性があります。これは、ストリームデータが再度受信されたときに新しいオブジェクトを作成することです。
var obs = Rx.Observable
.from(["a", "b", "c"])
.concatMap(value => Rx.Observable.of(value))
.scan((acc, value) => {
//clone initial value
if (acc.length == 0) {
acc = [];
}
acc.Push(value);
return acc
}, []); // Note that an empty array is use as the seed
obs.subscribe(value => console.log(JSON.stringify(value)));
obs.subscribe(value => console.log(JSON.stringify(value)));
期待どおりの結果:
["a"]
["a","b"]
["a","b","c"]
["a"]
["a","b"]
["a","b","c"]
私はそれが誰かのために多くの時間を節約することを望みます