2012-05-03 5 views
5

मैं साधारण जोड़ी वर्ग का एक बड़ा संग्रह मिल गया है। मैं उचित समय पर सूची में प्रत्येक आइटम के लिए मूल्य (कहें, एक्शन < डबल >) के साथ एक ईवेंट ट्रिगर करना चाहता हूं। समय अतीत में है, इसलिए मुझे टाइमस्टैम्प को सामान्यीकृत करने की आवश्यकता है जैसे कि सूची में पहला "अब" है। क्या हम इसे प्रतिक्रियाशील एक्सटेंशन के साथ सेट कर सकते हैं जैसे कि यह दो आइटमों के बीच के अंतर के बाद अगली घटना को ट्रिगर करता है?विभिन्न समय पर घटनाओं को ट्रिगर करने के लिए आरएक्स का उपयोग करें?</p> <pre><code>public class Pair { public DateTime Timestamp; public double Value; } </code></pre> <p>वे आरोही टाइमस्टैम्प द्वारा हल कर रहे हैं:

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

अब obs एक आदेश दिया नमूदार के रूप में जोड़े है:

+0

क्या आपने http://reactiveproperty.codeplex.com/ पर एक नज़र डाली है? – dwerner

उत्तर

6

कहो pairs अपने अनुक्रम है।

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

ज़िप पूर्ण समय को ऑफसेट में बदलने का ख्याल रखता है। के रूप में

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

इस प्रकार इस नई मूल्य तो यह उचित मात्रा में देरी करने के लिए Observable.Timer में डाल दिया है यह, अनुक्रम का समय लगेगा और साथ ही इसमें शामिल होने के लिए, लेकिन ऑफसेट एक एक करके। अंतिम ConcatIObservable<IObservable<double>> से IObservable<double> में परिणाम को फ़्लैट करता है। यह मानता है कि आपके अनुक्रम का आदेश दिया गया है।

+0

अच्छा समाधान। मैं 'var orderObs = pair.OrderBy (p => p.Timestamp) जोड़ूंगा। ToObservable() 'यह स्पष्ट करने के लिए कि क्या होने की आवश्यकता है और इसके बजाय इसका उपयोग करें। मैंने इन परिवर्तनों को बनाया .. – yamen

+0

इससे बहुत मदद मिलती है। मैंने इसे ऐतिहासिक डेटा से पूछताछ करने के लिए उपयोग किया और इसे मूल रूप से रिकॉर्ड किया गया था जैसे इसे वापस चलाएं। नई प्रणाली काम साबित करने के लिए एक सिम्युलेटर। –

+0

मुझे पता लगाने के लिए थोड़ी देर लग गई कि वास्तव में क्या चल रहा था, लेकिन मुझे अब यह मिल गया है। आरएक्स एक दिमागी *** है। हालांकि बहुत बढ़िया समाधान। +1 – BFree

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(); 
} 
+0

यह वास्तव में अनिवार्य रूप से जटिल है क्योंकि आरएक्स के पास 'टाइमर', 'डीफर' और 'देरी' जैसे एक्सटेंशन हैं। – yamen

+0

@Yamen मैंने कभी आरएक्स का उपयोग नहीं किया है, न ही वास्तव में योजना है। मैं जवाब देना चाहता था कि इसे चुनौती के रूप में खरोंच से कैसे किया जाए क्योंकि मैंने सोचा था कि यह अंतःस्थापित था :) क्षमा करें अगर इस संदर्भ में मेरा जवाब केवल स्पैम है। – payo

+2

माफी माँगने की कोई ज़रूरत नहीं है, मुझे उम्मीद है कि आप ऊपर आरएक्स समाधान से कुछ सीखेंगे। आपका उत्तर वास्तव में एक उदाहरण के रूप में कार्य करता है कि क्यों आरएक्स महान है :-) – yamen

2

"आरएक्स का उपयोग कर" द्वारा तुम मुझे सिर्फ आरएक्स शेड्यूलर उपयोग करने की अनुमति है, तो यह एक बहुत ही आसान समाधान है:

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, }, 
}; 

मुझे आशा है कि इस मदद करता है।

+0

क्या शेड्यूलर की अपनी कतार है? या यह कोड पूरे थ्रेडपूल को चबाएगा? मैं इस समाधान की स्केलेबिलिटी के बारे में चिंतित हूं। – Brannon

+0

@ ब्रैनन - अगर मुझे सही ढंग से शेड्यूलर याद आते हैं तो क्रियाओं को कतार में आंतरिक रूप से एक हीप प्रकार का उपयोग करें।इसके अलावा एक शेड्यूलर केवल एक ही समय में एक क्रिया निष्पादित करेगा और वर्तमान थ्रेड का पुन: उपयोग करेगा यदि कोई अन्य कार्य तुरंत जाने के लिए तैयार है। तो वे एक समय में केवल एक धागे का उपयोग करते हैं। – Enigmativity

संबंधित मुद्दे

 संबंधित मुद्दे