2つのデータソースがあります。
それらの1つはキャッシュされたリストであり、もう1つはを介してプッシュされた新しいデータIObservable<T>
です。
Rxを使用して、キャッシュされたリストAに対して実行する必要のある操作を見つけ、その順序と内容を新しいデータと同一にする必要があります。
IEnumerable<T> a
とを取り、操作(挿入と削除)IObservable<T> b
をプッシュするオブザーバブルを返す関数を探しています。これにより、完了するのを待たずに同じになります。a
b
b
注:リストまたはオブザーバブルを変更できないことはわかっています。したくない。
これらの操作がわかるとすぐに、どの操作、どの順序で、Aと同じ順序と順序の仮想リストがBと同じ順序と順序のリストに変わるかを知りたいだけです。
a
とは両方ともb
一意でソートされており、とをT
実装IComparable<T>
しIEquatable<T>
ます。
public static IObservable<Tuple<int, bool>> IndexDelta<T>(
IEnumerable<T> a,
IObservable<T> b
) where T : IEquatable<T>, IComparable<T> {
// ???
}
int
私の例ではsを使用します。
何?!
次の2つのシーケンスを検討してください。
A: [150, 100, 70, 30, 20]
B: [300, 200, 100, 70, 60, 50, 20]
目標は、AをBに変換する一連の削除/挿入操作を見つけることです。Aはキャッシュされたデータソース、Bは新しいデータであると考えてください。これらの更新を、リロードせずにグリッドに変換する方法を知りたいです。
行は両方のソースでソートされます。
出力を形式にしたい
[(0, true), (1, true), (0, false), (3, false), (4, true), (5, true)]
後でこれらの操作をブールフラグでグループ化します。
deleted: [0, 3]
inserted: [0, 1, 4, 5]
これは人間の言語に次のように翻訳されます
A0とA3を削除します。
A = [
150、100、70、30、20] = [100、70、20]B 0、B 1、B 4、B5をAに挿入します。
A = [ 300、200、100、70、60、50、20 ] _ _ _ _
これで、AはBと同じになります。
要件
私が注意したいいくつかの重要なことがあります:
Aは変更されないことが保証されているリストです。Bはコールドオブザーバブルであり、完了するまでに時間がかかりますが、すぐに最初のアイテムが生成されます。したがって、十分なデータが利用可能になったらすぐに、オブザーバブルの結果をプッシュする必要があります。
アイテムは、両方のソースで一意であることが保証されています。
IEquatable<T>
アイテムは変更不可能であり、両方のソースを使用して降順でソートされることが保証されています。
IComparable<T>
Bの左側に追加される新しいアイテムに合わせて最適化することをお勧めします。これは最も一般的なシナリオです。ただし、タイムスタンプが適切であれば、アイテムが他の場所で削除または挿入される可能性があります(並べ替えを損なうことはありません)。iPhoneのカメラロールを考えてみてください。
(*)可能であれば、純粋な機能ソリューションに興味があります。
擬似コードスケッチ
これを必須の方法で実装する擬似コードアルゴリズムをスケッチしました。
私は、、、およびセマンティクスを作成しましたCurrent
が、MoveNext
アイデアはある程度意味があるはずです。await
yield push
IObservable<Tuple<int, bool>> IndexDelta(a, b)
{
var indexA = 0;
var indexB = 0;
while (true) {
var headA = a.Current;
var headB = b.Current;
if (headA == null && headB == null) {
return yield break; // both sequences are over
}
var reportDeletion = () => {
yield push Tuple.Create(indexA, false);
await a.MoveNext(); // this one is fast
}
var reportInsertion = () => {
yield push Tuple.Create(indexB, true);
await b.MoveNext(); // can take a long time
}
if (headA == null) { // No source item at this position
reportInsertion();
continue;
}
if (headB == null) { // No fetched item at this position
reportDeletion();
continue;
}
switch (headB.CompareTo(headA)) {
case 0:
yield continue;
break;
case 1: // Fetched item is newer than source item
reportInsertion();
break;
case -1: // Source item is newer than fetched item
reportDeletion();
break;
}
indexA++;
indexB++;
}
}
と非常によく似たものを実装できると思いますSubject<T>
。Aggregate
ただし、、、などのRx関数を作成するだけで解決できるZip
かどうか疑問に思っているので、この解決策を進めたくありませんCombineLatest
。
あなたの考えは何ですか?