5

私は単純なペアクラスの大きなコレクションを持っています:

public class Pair { public DateTime Timestamp; public double Value; }

昇順のタイムスタンプで並べ替えられます。適切なタイミングで、リスト内の各項目の値 (Action<double> など) を使用してイベントをトリガーしたいと考えています。時刻は過去のものなので、リストの最初のタイムスタンプが「今」になるようにタイムスタンプを正規化する必要があります。2 つのアイテム間の時間差の後に次のイベントをトリガーするように、Reactive Extensions でこれを設定できますか?

4

3 に答える 3

7

あなたpairsのシーケンスは次のとおりです。

var obs = pairs.OrderBy(p => p.Timestamp).ToObservable();

obsこれで、順序付けられたオブザーバブルとしてのペアになります。

Observable.Zip(
    obs,
    obs.Take(1).Concat(obs),
    (pair1, pair2) => Observable.Timer(pair1.Timestamp - pair2.Timestamp)
      .Select(_ => pair1.Value))
.Concat()
.Subscribe(/* Do something here */);

zipは、絶対時間をオフセットに変換する処理を行います。シーケンスを取得してそれ自体と結合しますが、次のように1つオフセットされます

Original 1--2--4--7--11
Offset   1--1--2--4--7--11
Joined   0--1--2--3--4

次に、この新しい値をに入れてObservable.Timer、適切な量だけ遅延させます。ファイナルConcatは、からの結果を。にフラットIObservable<IObservable<double>>化しIObservable<double>ます。これは、シーケンスが順序付けられていることを前提としています。

于 2012-05-03T23:49:21.187 に答える
2

「Rx を使用する」ことで Rx スケジューラのみを使用できるようにする場合、これは非常に簡単な解決策です。

Action<double> action =
    x =>
        Console.WriteLine(x);

var ts0 = pairs.Select(p => p.Timestamp).Min();

pairs
    .ForEach(p => 
        Scheduler
            .ThreadPool
            .Schedule(
                p.Timestamp.Subtract(ts0),
                () => action(p.Value)));

これはSystem.Interactive拡張機能を使用しますが、通常のループをForEach使用してスケジューラをロードすることもできます。foreach

次のダミーデータを使用してコードをテストしました。

var pairs = new []
{
    new Pair { Timestamp = new DateTime(2011, 1, 1, 7, 12, 30), Value = 1.1, },
    new Pair { Timestamp = new DateTime(2011, 1, 1, 7, 12, 45), Value = 1.2, },
    new Pair { Timestamp = new DateTime(2011, 1, 1, 7, 12, 40), Value = 1.3, },
};

これが役立つことを願っています。

于 2012-05-04T00:57:38.007 に答える
0

この問題は面白いと思います。これは私の最初の試みです。

static void RunPairs(IEnumerable<Pair> pairs, Action<double> pairEvent)
{
  if (pairs == null || !pairs.Any() || pairEvent == null)
    return;

  // if we can promise the pairs are already sorted
  // obviously we don't need this next line
  pairs = pairs.OrderBy(p => p.Timestamp);
  var first = pairs .First().Timestamp;
  var wrapped = pairs.Select(p => new { Offset = (p.Timestamp - first), Pair = p });

  var start = DateTime.Now;

  double interval = 250; // 1/4 second
  Timer timer = new Timer(interval);

  timer.AutoReset = true;
  timer.Elapsed += (sender, elapsedArgs) =>
  {
    var signalTime = elapsedArgs.SignalTime;
    var elapsedTime = (signalTime - start);

    var pairsToTrigger = wrapped.TakeWhile(wrap => elapsedTime > wrap.Offset).Select(w => w.Pair);
    wrapped = wrapped.Skip(pairsToTrigger.Count());

    if (!wrapped.Any())
      timer.Stop();

    foreach (var pair in pairsToTrigger)
      pairEvent(pair.Value);    
  };

  timer.Start();
}
于 2012-05-03T23:55:52.090 に答える