0

I am trying RxJS.

My use case is to parse a log file and group lines by topic ( i.e.: the beginning of the group is the filename and then after that I have some lines with user, date/time and so on) I can analyse the lines using regExp. I can determine the beginning of the group.

I use ".scan" to group the lines together, when I've the beginning of new group of line, I create an observer on the lines I've accumulated ... fine.

The issue is the end of the file. I've started a new group, I am accumulating lines but I can not trigger the last sequence as I do not have the information that the end. I would have expect to have the information in the complete (but not)

Here is an example using number. Begin of group can multi of 3 or 5. (remark: I work in typescript)

import * as Rx from "rx";

let r = Rx.Observable
        .range(0, 8)
        .scan( function(acc: number[], value: number): number[]{
            if (( value % 3 === 0) || ( value % 5 === 0)) {
                acc.push(value);
                let info = acc.join(".");
                Rx.Observable
                    .fromArray(acc)
                    .subscribe( (value) => {
                        console.log(info, "=>", value);
                    });
                acc = [];
            } else {
                acc.push(value);
            }
            return acc;
        }, [])
        .subscribe( function (x) {
            // console.log(x);
        });  

This emit:

 0 => 0
 1.2.3 => 1
 1.2.3 => 2
 1.2.3 => 3
 4.5 => 4
 4.5 => 5
 6 => 6

I am looking how to emit

 0 => 0
 1.2.3 => 1
 1.2.3 => 2
 1.2.3 => 3
 4.5 => 4
 4.5 => 5
 6 => 6
 7.8 => 7     last items are missing as I do not know how to detect end
 7.8 => 8        

Can you help me, grouping items? Any good idea, even not using scan, is welcome.

Thank in advance

rlasjunies
  • 319
  • 1
  • 5
  • 11

1 Answers1

1

You can use the materialize operator. See the documentation here and the marbles here, and an example of use from SO.

In your case, I would try something like (untested but hopefully you can complete it yourself, note that I don't know a thing about typescript so there might be some syntax errors):

import * as Rx from "rx";

let r = Rx.Observable
        .range(0, 8)
        .materialize()
        .scan( function(acc: number[], materializedNumber: Rx.Notification<number>): number[]{
            let rangeValue: number = materializedNumber.value;

            if (( rangeValue % 3 === 0) || ( rangeValue % 5 === 0)) {
                acc.push(rangeValue);
                generateNewObserverOnGroupOf(acc);
                acc = [];
            } else if ( materializedNumber.kind === "C") {
                generateNewObserverOnGroupOf(acc);
                acc = [];
            } else {
                acc.push(rangeValue);
            }
            return acc;
        }, [])
        // .dematerialize()
        .subscribe( function (x) {
            // console.log(x);
        });

function generateNewObserverOnGroupOf(acc: number[]) {
    let info = acc.join(".");
                Rx.Observable
                    .fromArray(acc)
                    .subscribe( (value) => {
                        console.log(info, "=>", value);
                    });

The idea is that the materialize and dematerialize works with notifications, which encodes whether the message being passed by the stream is one of next, error, completed kinds (respectively 'N', 'E', 'C' values for the kind property). If you have a next notification, then the value passed is in the value field of the notification object. Note that you need to dematerialize to return to the normal behaviour of the stream so it can complete and free resources when finished.

Community
  • 1
  • 1
user3743222
  • 18,345
  • 5
  • 69
  • 75