Q:

Transform Observable based on previous values

I have stream of events of 20 different types. 
I would like set a boolean for each event if an event of similar type was emitted within the last 10 seconds. 
This should happen live, I don't want to delay the events for 10 seconds.
The event stream is continuous and does not end

Can this be done with RxJs? 
UPDATE: Here is a JsBin demo of my event stream (Please take a look at the comments) http://jsbin.com/jepesu/1/edit?js,console,output

A:

I found a solution to my problem. The events look like this:
{
  id: 0,            // unique
  title: 'xxx',
  sound: 'p0',      // One of 'p0', 'p1', 'p2'
  playSound: false, // If the sound should be played
}

Sounds shall only be played if a sound of the same type wasn't played in the last 5 seconds. playSound is the boolean I want to toggle. For that I need a helper function: throttleMap
/**
 * Executes a map function on the first element in the window, returns the rest as is
 * In other words: Executes mapFunction on all elements the Rx.throttle() function would
 * emit, emits all other elements unchanged
 */
Rx.Observable.prototype.throttleMap = function (windowDuration, mapFunction, scheduler) {
    Rx.Scheduler.isScheduler(scheduler) || (scheduler = Rx.Scheduler.default);
    var duration = +windowDuration || 0;
    if (duration <= 0) { throw new RangeError('windowDuration cannot be less or equal zero.'); }
    var source = this;
    return new Rx.AnonymousObservable(function (o) {
      var lastOnNext = 0;
      return source.subscribe(
        function (x) {
          var now = scheduler.now();
          if (lastOnNext === 0 || now - lastOnNext >= duration) {
            lastOnNext = now;
            o.onNext(mapFunction(x));
          }
          else {
            o.onNext(x);
          }
        },function (e) { o.onError(e); }, function () { o.onCompleted(); }
      );
    }, source);
  };

Now the solution:
const groupedSoundStream = singleNotificationStream
  .groupBy(
    (x) => x.sound,
    (x) => x
  )
  .flatMap((x) => {
    return x.throttleMap(5000, (x) => {
      x.playSound = true
      return x
    })
  })

 groupedSoundStream
   .subscribe((x) => console.log(secSinceStart()+'s', x))

Some sample output:
0.3s { id: 0,  title: 'M#0',  sound: 'p2', playSound: true  }
0.6s { id: 1,  title: 'M#1',  sound: 'p1', playSound: true  }
0.9s { id: 2,  title: 'M#2',  sound: 'p1', playSound: false }
1.2s { id: 3,  title: 'M#3',  sound: 'p0', playSound: true  }
1.5s { id: 4,  title: 'M#4',  sound: 'p2', playSound: false }
1.8s { id: 5,  title: 'M#5',  sound: 'p0', playSound: false }
2.1s { id: 6,  title: 'M#6',  sound: 'p1', playSound: false }
2.4s { id: 7,  title: 'M#7',  sound: 'p2', playSound: false }
2.7s { id: 8,  title: 'M#8',  sound: 'p2', playSound: false }
3.1s { id: 9,  title: 'M#9',  sound: 'p1', playSound: false }
3.4s { id: 10, title: 'M#10', sound: 'p1', playSound: false }
3.7s { id: 11, title: 'M#11', sound: 'p1', playSound: false }
4s   { id: 12, title: 'M#12', sound: 'p2', playSound: false }
4.3s { id: 13, title: 'M#13', sound: 'p0', playSound: false }
4.6s { id: 14, title: 'M#14', sound: 'p2', playSound: false }
4.9s { id: 15, title: 'M#15', sound: 'p1', playSound: false }
5.2s { id: 16, title: 'M#16', sound: 'p2', playSound: false }
5.5s { id: 17, title: 'M#17', sound: 'p2', playSound: true  }
5.8s { id: 18, title: 'M#18', sound: 'p0', playSound: false }
6.1s { id: 19, title: 'M#19', sound: 'p2', playSound: false }
6.4s { id: 20, title: 'M#20', sound: 'p1', playSound: true  }
6.7s { id: 21, title: 'M#21', sound: 'p2', playSound: false }
7s   { id: 22, title: 'M#22', sound: 'p1', playSound: false }

