code: def find_ngrams(
      tokens: typing.Iterator[str], n: int
  ) -> typing.Iterator[N_GRAM]:
      """Generates n-grams from a list of tokens.
  
      From http://www.locallyoptimal.com/blog/2013/01/20/elegant-n-gram-generation-in-python/.
  
      Examples
      --------
  
      >>> tokens = ['a', 'b', 'c']
  
      >>> list(find_ngrams(tokens, 0))
      []
  
      >>> list(find_ngrams(tokens, 1))
      ['a', 'b', 'c']
  
      >>> list(find_ngrams(tokens, 2))
      [('a', 'b'), ('b', 'c')]
  
      >>> list(find_ngrams(tokens, 3))
      [('a', 'b', 'c')]
  
      >>> list(find_ngrams(tokens, 4))
      []
  
      """
      if n == 1:
          return tokens
  
      # This seems to be slightly faster than the sliding_window
      # from https://docs.python.org/3/library/itertools.html#itertools-recipes.
      neighbors = itertools.tee(tokens, n)
      for i in range(1, n):
          for j in range(i, n):
              next(neighbors[j], None)
      return zip(*neighbors)
  
imports: from __future__ import annotations
  import collections
  import functools
  import itertools
  import math
  import operator
  import re
  import typing
  import unicodedata
  import pandas
  from scipy import sparse
  from river import base
label_desc: Use image node_id 4 for calling a global function with example usage: find_ngrams(tokens, n) and returns: zip, tokens