nodes: 0, module; 1, function_definition; 2, function_name:group_items; 3, parameters; 4, block; 5, identifier:items; 6, default_parameter; 7, default_parameter; 8, expression_statement; 9, if_statement; 10, comment:# Initialize a dict of lists; 11, expression_statement; 12, comment:# Insert each item into the correct group; 13, for_statement; 14, return_statement; 15, identifier:by; 16, None; 17, identifier:sorted_; 18, True; 19, comment:"""
      Groups a list of items by group id.
  
      Args:
          items (list): a list of the values to be grouped.
              if `by` is None, then each item is assumed to be a
              (groupid, value) pair.
          by (list): a corresponding list to group items by.
              if specified, these are used as the keys to group values
              in `items`
          sorted_ (bool): if True preserves the ordering of items within groups
              (default = True) FIXME. the opposite is true
  
      Returns:
          dict: groupid_to_items: maps a groupid to a list of items
  
      SeeAlso:
          group_indices - first part of a a more fine grained grouping algorithm
          apply_gropuing - second part of a more fine grained grouping algorithm
  
      CommandLine:
          python -m utool.util_dict --test-group_items
  
      Example:
          >>> # ENABLE_DOCTEST
          >>> from utool.util_dict import *  # NOQA
          >>> import utool as ut
          >>> items = ['ham',     'jam',   'spam',     'eggs',    'cheese', 'bannana']
          >>> by    = ['protein', 'fruit', 'protein',  'protein', 'dairy',  'fruit']
          >>> groupid_to_items = ut.group_items(items, iter(by))
          >>> result = ut.repr2(groupid_to_items)
          >>> print(result)
          {'dairy': ['cheese'], 'fruit': ['jam', 'bannana'], 'protein': ['ham', 'spam', 'eggs']}
      """; 20, comparison_operator:by is not None; 21, block; 22, else_clause; 23, assignment; 24, pattern_list; 25, identifier:pairs; 26, block; 27, identifier:groupid_to_items; 28, identifier:by; 29, None; 30, expression_statement; 31, if_statement; 32, block; 33, identifier:groupid_to_items; 34, call; 35, identifier:groupid; 36, identifier:item; 37, expression_statement; 38, assignment; 39, identifier:sorted_; 40, comment:# Sort by groupid for cache efficiency (does this even do anything?); 41, comment:# I forgot why this is needed? Determenism?; 42, block; 43, expression_statement; 44, identifier:defaultdict; 45, argument_list; 46, call; 47, identifier:pairs; 48, call; 49, try_statement; 50, assignment; 51, identifier:list; 52, attribute; 53, argument_list; 54, identifier:list; 55, argument_list; 56, block; 57, except_clause; 58, identifier:pairs; 59, identifier:items; 60, subscript; 61, identifier:append; 62, identifier:item; 63, call; 64, expression_statement; 65, identifier:TypeError; 66, comment:# Python 3 does not allow sorting mixed types; 67, block; 68, identifier:groupid_to_items; 69, identifier:groupid; 70, identifier:zip; 71, argument_list; 72, assignment; 73, expression_statement; 74, identifier:by; 75, identifier:items; 76, identifier:pairs; 77, call; 78, assignment; 79, identifier:sorted; 80, argument_list; 81, identifier:pairs; 82, call; 83, identifier:pairs; 84, keyword_argument; 85, identifier:sorted; 86, argument_list; 87, identifier:key; 88, call; 89, identifier:pairs; 90, keyword_argument; 91, attribute; 92, argument_list; 93, identifier:key; 94, lambda; 95, identifier:op; 96, identifier:itemgetter; 97, integer:0; 98, lambda_parameters; 99, call; 100, identifier:tup; 101, identifier:str; 102, argument_list; 103, subscript; 104, identifier:tup; 105, integer:0
code: def group_items(items, by=None, sorted_=True):
      """
      Groups a list of items by group id.
  
      Args:
          items (list): a list of the values to be grouped.
              if `by` is None, then each item is assumed to be a
              (groupid, value) pair.
          by (list): a corresponding list to group items by.
              if specified, these are used as the keys to group values
              in `items`
          sorted_ (bool): if True preserves the ordering of items within groups
              (default = True) FIXME. the opposite is true
  
      Returns:
          dict: groupid_to_items: maps a groupid to a list of items
  
      SeeAlso:
          group_indices - first part of a a more fine grained grouping algorithm
          apply_gropuing - second part of a more fine grained grouping algorithm
  
      CommandLine:
          python -m utool.util_dict --test-group_items
  
      Example:
          >>> # ENABLE_DOCTEST
          >>> from utool.util_dict import *  # NOQA
          >>> import utool as ut
          >>> items = ['ham',     'jam',   'spam',     'eggs',    'cheese', 'bannana']
          >>> by    = ['protein', 'fruit', 'protein',  'protein', 'dairy',  'fruit']
          >>> groupid_to_items = ut.group_items(items, iter(by))
          >>> result = ut.repr2(groupid_to_items)
          >>> print(result)
          {'dairy': ['cheese'], 'fruit': ['jam', 'bannana'], 'protein': ['ham', 'spam', 'eggs']}
      """
      if by is not None:
          pairs = list(zip(by, items))
          if sorted_:
              # Sort by groupid for cache efficiency (does this even do anything?)
              # I forgot why this is needed? Determenism?
              try:
                  pairs = sorted(pairs, key=op.itemgetter(0))
              except TypeError:
                  # Python 3 does not allow sorting mixed types
                  pairs = sorted(pairs, key=lambda tup: str(tup[0]))
      else:
          pairs = items
  
      # Initialize a dict of lists
      groupid_to_items = defaultdict(list)
      # Insert each item into the correct group
      for groupid, item in pairs:
          groupid_to_items[groupid].append(item)
      return groupid_to_items