github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/isc/stream.go (about)

     1  package isc
     2  
     3  import (
     4  	"sort"
     5  )
     6  
     7  // A Stream is a stream that can be used to do stream processing.
     8  type Stream[T any] struct {
     9  	source <-chan T
    10  }
    11  
    12  // StreamJust converts the given arbitrary items to a Stream.
    13  func StreamJust[T any](items ...T) Stream[T] {
    14  	source := make(chan T, len(items))
    15  	for _, e := range items {
    16  		source <- e
    17  	}
    18  	close(source)
    19  	return StreamRange(source)
    20  }
    21  
    22  // AllMatch returns whether all elements of this stream match the provided predicate.
    23  // May not evaluate the predicate on all elements if not necessary for determining the result.
    24  // If the stream is empty then true is returned and the predicate is not evaluated.
    25  func (s Stream[T]) AllMatch(predicate func(T) bool) bool {
    26  	for item := range s.source {
    27  		if !predicate(item) {
    28  			// make sure the former goroutine not block, and current func returns fast.
    29  			go StreamDrain(s.source)
    30  			return false
    31  		}
    32  	}
    33  	return true
    34  }
    35  
    36  // AnyMatch returns whether any elements of this stream match the provided predicate.
    37  // May not evaluate the predicate on all elements if not necessary for determining the result.
    38  // If the stream is empty then false is returned and the predicate is not evaluated.
    39  func (s Stream[T]) AnyMatch(predicate func(T) bool) bool {
    40  	for item := range s.source {
    41  		if predicate(item) {
    42  			// make sure the former goroutine not block, and current func returns fast.
    43  			go StreamDrain(s.source)
    44  			return true
    45  		}
    46  	}
    47  	return false
    48  }
    49  
    50  // NoneMatch returns whether all elements of this stream don't match the provided predicate.
    51  // May not evaluate the predicate on all elements if not necessary for determining the result.
    52  // If the stream is empty then true is returned and the predicate is not evaluated.
    53  func (s Stream[T]) NoneMatch(predicate func(T) bool) bool {
    54  	for item := range s.source {
    55  		if predicate(item) {
    56  			go StreamDrain(s.source)
    57  			return false
    58  		}
    59  	}
    60  	return true
    61  }
    62  
    63  func (s Stream[T]) Map(fn func(T) T) Stream[T] {
    64  	source := make(chan T)
    65  	for item := range s.source {
    66  		source <- fn(item)
    67  	}
    68  	return StreamRange(source)
    69  }
    70  
    71  // Sort sorts the items from the underlying source.
    72  func (s Stream[T]) Sort(less func(T, T) bool) Stream[T] {
    73  	var items []T
    74  	for item := range s.source {
    75  		items = append(items, item)
    76  	}
    77  	sort.Slice(items, func(i, j int) bool {
    78  		return less(items[i], items[j])
    79  	})
    80  	return StreamJust(items...)
    81  }
    82  
    83  // Distinct removes the duplicated items base on the given keySelector.
    84  func (s Stream[T]) Distinct(keySelector func(T) T) Stream[T] {
    85  	source := make(chan T)
    86  	m := make(map[any]T)
    87  	for item := range s.source {
    88  		m[keySelector(item)] = item
    89  	}
    90  	for _, v := range m {
    91  		source <- v
    92  	}
    93  	return StreamRange(source)
    94  }
    95  
    96  // ForEach seals the Stream with the fn on each item, no successive operations.
    97  func (s Stream[T]) ForEach(fn func(T)) {
    98  	for item := range s.source {
    99  		fn(item)
   100  	}
   101  }
   102  
   103  //FirsVal returns the first element,channel is FIFO,so first goroutine will get head element or nil
   104  func (s Stream[T]) FirsVal() any {
   105  	for item := range s.source {
   106  		go StreamDrain(s.source)
   107  		return item
   108  	}
   109  	return nil
   110  }
   111  
   112  //First returns the first element,channel is FIFO,so first goroutine will get head element
   113  func (s Stream[T]) First(valueSelector func(T) bool) Stream[T] {
   114  	source := make(chan T)
   115  	go func() {
   116  		for item := range s.source {
   117  			if valueSelector(item) {
   118  				source <- item
   119  				break
   120  			}
   121  		}
   122  	}()
   123  	close(source)
   124  	return StreamRange(source)
   125  }
   126  
   127  // LastVal returns the last item, or nil if no items.
   128  func (s Stream[T]) LastVal() (item T) {
   129  	for item = range s.source {
   130  	}
   131  	return
   132  }
   133  
   134  // Last returns the last item, or nil if no items.
   135  func (s Stream[T]) Last(valueSelector func(any) bool) Stream[T] {
   136  	source := make(chan T)
   137  	var lastValue T
   138  	for item := range s.source {
   139  		if valueSelector(item) {
   140  			lastValue = item
   141  		}
   142  	}
   143  	source <- lastValue
   144  	close(source)
   145  	return StreamRange(source)
   146  }
   147  
   148  //Filter Returns a list containing only elements matching the given predicate.
   149  func (s Stream[T]) Filter(predicate func(T) bool) Stream[T] {
   150  	source := make(chan T)
   151  	for item := range s.source {
   152  		if predicate(item) {
   153  			source <- item
   154  		}
   155  	}
   156  	defer close(source)
   157  	return StreamRange(source)
   158  }
   159  
   160  func StreamRange[T any](source <-chan T) Stream[T] {
   161  	return Stream[T]{
   162  		source: source,
   163  	}
   164  }
   165  
   166  // StreamDrain drains the given channel.
   167  func StreamDrain[T any](ch <-chan T) {
   168  	for range ch {
   169  	}
   170  }
   171  
   172  // Done waits all upstreaming operations to be done.
   173  func (s Stream[T]) Done() {
   174  	StreamDrain(s.source)
   175  }