RxJava पृष्ठभूमि से आते हुए, मैं RxSwift में स्लाइडिंग विंडो को लागू करने के लिए एक मानक दृष्टिकोण के साथ नहीं आ सकता। जैसे मेरे पास घटनाओं का निम्नलिखित क्रम है:

1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ...

आइए कल्पना करें कि घटना उत्सर्जन एक सेकंड में दो बार होता है। मैं जो करने में सक्षम होना चाहता हूं वह इस अनुक्रम को बफर के अनुक्रम में बदलना है, प्रत्येक बफर में डेटा के अंतिम तीन सेकंड होते हैं। साथ ही, प्रत्येक बफर को एक सेकंड में एक बार उत्सर्जित किया जाना है। तो परिणाम इस तरह दिखेगा:

[1,2,3,4,5,6], [3,4,5,6,7,8], [5,6,7,8,9,10], ...

मैं RxJava में क्या करूँगा मैं buffer विधि के अधिभारों में से एक का उपयोग इस प्रकार करूंगा:

stream.buffer(3000, 1000, TimeUnit.MILLISECONDS)

जो वास्तव में उस परिणाम की ओर जाता है जिसे मुझे पूरा करने की आवश्यकता है: बफ़र्स का अनुक्रम, प्रत्येक बफर एक सेकंड में एक बार उत्सर्जित होता है और इसमें अंतिम तीन सेकंड का डेटा होता है।

मैंने दूर-दूर तक RxSwift डॉक्स की जाँच की और मुझे buffer ऑपरेटर का कोई भी ओवरलोड नहीं मिला जो मुझे ऐसा करने की अनुमति दे। क्या मुझे कुछ गैर-स्पष्ट (आरएक्सजेवा उपयोगकर्ता, ओसीसी) ऑपरेटर याद आ रहा है?

0
aga 17 पद 2018, 12:00

2 जवाब

सबसे बढ़िया उत्तर

मैंने शुरुआत में एक कस्टम ऑपरेटर का उपयोग करके समाधान लिखा था। मैंने तब से यह पता लगाया है कि यह मानक ऑपरेटरों के साथ कैसे किया जा सकता है।

extension ObservableType {

    func buffer(timeSpan: RxTimeInterval, timeShift: RxTimeInterval, scheduler: SchedulerType) -> Observable<[E]> {
        let trigger = Observable<Int>.timer(timeSpan, period: timeShift, scheduler: scheduler)
            .takeUntil(self.takeLast(1))

        let buffer = self
            .scan([Date: E]()) { previous, current in
                var next = previous
                let now = scheduler.now
                next[now] = current
                return next.filter { $0.key > now.addingTimeInterval(-timeSpan) }
        }

        return trigger.withLatestFrom(buffer)
            .map { $0.sorted(by: { $0.key <= $1.key }).map { $0.value } }
    }
}

मैं अपने मूल समाधान को वंश के लिए नीचे छोड़ रहा हूं:


अपना खुद का ऑपरेटर लिखना यहां समाधान है।

extension ObservableType {

    func buffer(timeSpan: RxTimeInterval, timeShift: RxTimeInterval, scheduler: SchedulerType) -> Observable<[E]> {
        return Observable.create { observer in
            var buf: [Date: E] = [:]
            let lock = NSRecursiveLock()
            let elementDispoable = self.subscribe { event in
                lock.lock(); defer { lock.unlock() }
                switch event {
                case let .next(element):
                    buf[Date()] = element
                case .completed:
                    observer.onCompleted()
                case let .error(error):
                    observer.onError(error)
                }
            }
            let spanDisposable = scheduler.schedulePeriodic((), startAfter: timeSpan, period: timeShift, action: { state in
                lock.lock(); defer { lock.unlock() }
                let now = Date()
                buf = buf.filter { $0.key > now.addingTimeInterval(-timeSpan) }
                observer.onNext(buf.sorted(by: { $0.key <= $1.key }).map { $0.value })
            })
            return Disposables.create([spanDisposable, elementDispoable])
        }
    }
}
2
Daniel T. 18 पद 2018, 15:55

कुछ परीक्षण और त्रुटि के बाद मैं निम्नलिखित समाधान के साथ आया हूं। हालांकि मैंने इसका परीक्षण नहीं किया, यह सिर्फ एक सामान्य विचार है (कृपया कोड को क्षमा करें, यह स्विफ्ट में मेरा दूसरा दिन लेखन है):

stream
    // split into a sequence of buffers where each buffer 
    // contains the data obtained during the last second  
    .buffer(timeSpan: RxTimeInterval(1), count: Int.max, scheduler: MainScheduler.instance)

    // put it into a temporary seed array; if array's length is 3 
    // then it contains last three seconds of data already
    // so we need to drop first second of data
    .scan([[AccelerometerReading]]()) accumulator: { (seed, lastSecond) -> [[AccelerometerReading]] in
        var mutable = seed
        if seed.count == 3 {
            mutable.remove(at: 0)
        }
        mutable.append(lastSecond)
        return mutable
    }

    // skip the first two windows as they're too short:
    // first one contains first second of data, second contains
    // first and second seconds of data
    .skip(2)

    // flatten a seed into one dimensional array
    .map { (window: [[AccelerometerReading]]) -> [AccelerometerReading] in
        window.flatMap { $0 }
    }
-1
aga 17 पद 2018, 18:16