@@ -660,13 +660,19 @@ class accumulate(Stream):
660660 This performs running or cumulative reductions, applying the function
661661 to the previous total and the new element. The function should take
662662 two arguments, the previous accumulated state and the next element and
663- it should return a new accumulated state.
663+ it should return a new accumulated state,
664+ - ``state = func(previous_state, new_value)`` (returns_state=False)
665+ - ``state, result = func(previous_state, new_value)`` (returns_state=True)
666+
667+ where the new_state is passed to the next invocation. The state or result
668+ is emitted downstream for the two cases.
664669
665670 Parameters
666671 ----------
667672 func: callable
668673 start: object
669- Initial value. Defaults to the first submitted element
674+ Initial value, passed as the value of ``previous_state`` on the first
675+ invocation. Defaults to the first submitted element
670676 returns_state: boolean
671677 If true then func should return both the state and the value to emit
672678 If false then both values are the same, and func returns one value
@@ -675,14 +681,41 @@ class accumulate(Stream):
675681
676682 Examples
677683 --------
684+ A running total, producing triangular numbers
685+
678686 >>> source = Stream()
679687 >>> source.accumulate(lambda acc, x: acc + x).sink(print)
680688 >>> for i in range(5):
681689 ... source.emit(i)
690+ 0
682691 1
683692 3
684693 6
685694 10
695+
696+ A count of number of events (including the current one)
697+
698+ >>> source = Stream()
699+ >>> source.accumulate(lambda acc, x: acc + 1, start=0).sink(print)
700+ >>> for _ in range(5):
701+ ... source.emit(0)
702+ 1
703+ 2
704+ 3
705+ 4
706+ 5
707+
708+ Like the builtin "enumerate".
709+
710+ >>> source = Stream()
711+ >>> source.accumulate(lambda acc, x: ((acc[0] + 1, x), (acc[0], x)),
712+ ... start=(0, 0), returns_state=True
713+ ... ).sink(print)
714+ >>> for i in range(3):
715+ ... source.emit(0)
716+ (0, 0)
717+ (1, 0)
718+ (2, 0)
686719 """
687720 _graphviz_shape = 'box'
688721
@@ -714,6 +747,54 @@ def update(self, x, who=None):
714747 return self ._emit (result )
715748
716749
750+ @Stream .register_api ()
751+ class slice (Stream ):
752+ """
753+ Get only some events in a stream by position. Works like list[] syntax.
754+
755+ Parameters
756+ ----------
757+ start : int
758+ First event to use. If None, start from the beginnning
759+ end : int
760+ Last event to use (non-inclusive). If None, continue without stopping.
761+ Does not support negative indexing.
762+ step : int
763+ Pass on every Nth event. If None, pass every one.
764+
765+ Examples
766+ --------
767+ >>> source = Stream()
768+ >>> source.slice(2, 6, 2).sink(print)
769+ >>> for i in range(5):
770+ ... source.emit(0)
771+ 2
772+ 4
773+ """
774+
775+ def __init__ (self , upstream , start = None , end = None , step = None , ** kwargs ):
776+ self .state = 0
777+ self .star = start or 0
778+ self .end = end
779+ self .step = step or 1
780+ if any ((_ or 0 ) < 0 for _ in [start , end , step ]):
781+ raise ValueError ("Negative indices not supported by slice" )
782+ stream_name = kwargs .pop ('stream_name' , None )
783+ Stream .__init__ (self , upstream , stream_name = stream_name )
784+ self ._check_end ()
785+
786+ def update (self , x , who = None ):
787+ if self .state >= self .star and self .state % self .step == 0 :
788+ self .emit (x )
789+ self .state += 1
790+ self ._check_end ()
791+
792+ def _check_end (self ):
793+ if self .end and self .state >= self .end :
794+ # we're done
795+ self .upstream .downstreams .remove (self )
796+
797+
717798@Stream .register_api ()
718799class partition (Stream ):
719800 """ Partition stream into tuples of equal size
@@ -748,10 +829,17 @@ def update(self, x, who=None):
748829class sliding_window (Stream ):
749830 """ Produce overlapping tuples of size n
750831
832+ Parameters
833+ ----------
834+ return_partial : bool
835+ If True, yield tuples as soon as any events come in, each tuple being
836+ smaller or equal to the window size. If False, only start yielding
837+ tuples once a full window has accrued.
838+
751839 Examples
752840 --------
753841 >>> source = Stream()
754- >>> source.sliding_window(3).sink(print)
842+ >>> source.sliding_window(3, return_partial=False ).sink(print)
755843 >>> for i in range(8):
756844 ... source.emit(i)
757845 (0, 1, 2)
@@ -763,14 +851,15 @@ class sliding_window(Stream):
763851 """
764852 _graphviz_shape = 'diamond'
765853
766- def __init__ (self , upstream , n , ** kwargs ):
854+ def __init__ (self , upstream , n , return_partial = True , ** kwargs ):
767855 self .n = n
768856 self .buffer = deque (maxlen = n )
857+ self .partial = return_partial
769858 Stream .__init__ (self , upstream , ** kwargs )
770859
771860 def update (self , x , who = None ):
772861 self .buffer .append (x )
773- if len (self .buffer ) == self .n :
862+ if self . partial or len (self .buffer ) == self .n :
774863 return self ._emit (tuple (self .buffer ))
775864 else :
776865 return []
0 commit comments