nodes: 0, module; 1, function_definition; 2, function_name:separate_groups; 3, parameters; 4, block; 5, identifier:groups; 6, identifier:key; 7, identifier:total; 8, expression_statement; 9, expression_statement; 10, expression_statement; 11, comment:# If every group is optimal return; 12, if_statement; 13, comment:# Some groups in optimal may have a number of elements that is optimum + 1.; 14, comment:# In this case they should be considered over_loaded.; 15, expression_statement; 16, expression_statement; 17, expression_statement; 18, expression_statement; 19, return_statement; 20, comment:"""Separate the group into overloaded and under-loaded groups.
  
      The revised over-loaded groups increases the choice space for future
      selection of most suitable group based on search criteria.
  
      For example:
      Given the groups (a:4, b:4, c:3, d:2) where the number represents the number
      of elements for each group.
      smart_separate_groups sets 'a' and 'c' as optimal, 'b' as over-loaded
      and 'd' as under-loaded.
  
      separate-groups combines 'a' with 'b' as over-loaded, allowing to select
      between these two groups to transfer the element to 'd'.
  
      :param groups: list of groups
      :param key: function to retrieve element count from group
      :param total: total number of elements to distribute
      :returns: sorted lists of over loaded (descending) and under
          loaded (ascending) group
      """; 21, assignment; 22, assignment; 23, not_operator; 24, block; 25, assignment; 26, assignment; 27, assignment; 28, assignment; 29, tuple; 30, pattern_list; 31, call; 32, pattern_list; 33, call; 34, identifier:extra; 35, return_statement; 36, identifier:potential_under_loaded; 37, list_comprehension; 38, identifier:potential_over_loaded; 39, list_comprehension; 40, identifier:revised_under_loaded; 41, binary_operator:under_loaded + potential_under_loaded; 42, identifier:revised_over_loaded; 43, binary_operator:over_loaded + potential_over_loaded; 44, call; 45, call; 46, identifier:optimum; 47, identifier:extra; 48, identifier:compute_optimum; 49, argument_list; 50, identifier:over_loaded; 51, identifier:under_loaded; 52, identifier:optimal; 53, identifier:_smart_separate_groups; 54, argument_list; 55, expression_list; 56, identifier:group; 57, for_in_clause; 58, if_clause; 59, identifier:group; 60, for_in_clause; 61, if_clause; 62, identifier:under_loaded; 63, identifier:potential_under_loaded; 64, identifier:over_loaded; 65, identifier:potential_over_loaded; 66, identifier:sorted; 67, argument_list; 68, identifier:sorted; 69, argument_list; 70, call; 71, identifier:total; 72, identifier:groups; 73, identifier:key; 74, identifier:total; 75, identifier:over_loaded; 76, identifier:under_loaded; 77, identifier:group; 78, identifier:optimal; 79, comparison_operator:key(group) == optimum; 80, identifier:group; 81, identifier:optimal; 82, comparison_operator:key(group) > optimum; 83, identifier:revised_over_loaded; 84, keyword_argument; 85, keyword_argument; 86, identifier:revised_under_loaded; 87, keyword_argument; 88, identifier:len; 89, argument_list; 90, call; 91, identifier:optimum; 92, call; 93, identifier:optimum; 94, identifier:key; 95, identifier:key; 96, identifier:reverse; 97, True; 98, identifier:key; 99, identifier:key; 100, identifier:groups; 101, identifier:key; 102, argument_list; 103, identifier:key; 104, argument_list; 105, identifier:group; 106, identifier:group
code: def separate_groups(groups, key, total):
      """Separate the group into overloaded and under-loaded groups.
  
      The revised over-loaded groups increases the choice space for future
      selection of most suitable group based on search criteria.
  
      For example:
      Given the groups (a:4, b:4, c:3, d:2) where the number represents the number
      of elements for each group.
      smart_separate_groups sets 'a' and 'c' as optimal, 'b' as over-loaded
      and 'd' as under-loaded.
  
      separate-groups combines 'a' with 'b' as over-loaded, allowing to select
      between these two groups to transfer the element to 'd'.
  
      :param groups: list of groups
      :param key: function to retrieve element count from group
      :param total: total number of elements to distribute
      :returns: sorted lists of over loaded (descending) and under
          loaded (ascending) group
      """
      optimum, extra = compute_optimum(len(groups), total)
      over_loaded, under_loaded, optimal = _smart_separate_groups(groups, key, total)
      # If every group is optimal return
      if not extra:
          return over_loaded, under_loaded
      # Some groups in optimal may have a number of elements that is optimum + 1.
      # In this case they should be considered over_loaded.
      potential_under_loaded = [
          group for group in optimal
          if key(group) == optimum
      ]
      potential_over_loaded = [
          group for group in optimal
          if key(group) > optimum
      ]
      revised_under_loaded = under_loaded + potential_under_loaded
      revised_over_loaded = over_loaded + potential_over_loaded
      return (
          sorted(revised_over_loaded, key=key, reverse=True),
          sorted(revised_under_loaded, key=key),
      )