code: def _smart_separate_groups(groups, key, total):
      
      optimum, extra = compute_optimum(len(groups), total)
      over_loaded, under_loaded, optimal = [], [], []
      for group in sorted(groups, key=key, reverse=True):
          n_elements = key(group)
          additional_element = 1 if extra else 0
          if n_elements > optimum + additional_element:
              over_loaded.append(group)
          elif n_elements == optimum + additional_element:
              optimal.append(group)
          elif n_elements < optimum + additional_element:
              under_loaded.append(group)
          extra -= additional_element
      return over_loaded, under_loaded, optimal
docs: Given a list of group objects, and a function to extract the number of
      elements for each of them, return the list of groups that have an excessive
      number of elements (when compared to a uniform distribution), a list of
      groups with insufficient elements, and a list of groups that already have
      the optimal number of elements.
  
      :param list groups: list of group objects
      :param func key: function to retrieve the current number of elements from the group object
      :param int total: total number of elements to distribute
  
      Example:
          .. code-block:: python
             smart_separate_groups([11,  9, 10, 14], lambda g: g) => ([14], [10, 9], [11])