code: def _groupby_and_merge(
      by, on, left, right, _merge_pieces, check_duplicates=True
  ):
      """
      groupby & merge; we are always performing a left-by type operation
  
      Parameters
      ----------
      by: field to group
      on: duplicates field
      left: left frame
      right: right frame
      _merge_pieces: function for merging
      check_duplicates: boolean, default True
          should we check & clean duplicates
      """
  
      pieces = []
      if not isinstance(by, (list, tuple)):
          by = [by]
  
      lby = left.groupby(by, sort=False)
  
      # if we can groupby the rhs
      # then we can get vastly better perf
      try:
          # we will check & remove duplicates if indicated
          if check_duplicates:
              if on is None:
                  on = []
              elif not isinstance(on, (list, tuple)):
                  on = [on]
  
              if right.duplicated(by + on).any():
                  right = right.drop_duplicates(by + on, keep="last")
          rby = right.groupby(by, sort=False)
      except KeyError:
          rby = None
  
      for key, lhs in lby:
          if rby is None:
              rhs = right
          else:
              try:
                  rhs = right.take(rby.indices[key])
              except KeyError:
                  # key doesn't exist in left
                  lcols = lhs.columns.tolist()
                  cols = lcols + [
                      r for r in right.columns if r not in set(lcols)
                  ]
                  merged = lhs.reindex(columns=cols)
                  merged.index = range(len(merged))
                  pieces.append(merged)
                  continue
  
          merged = _merge_pieces(lhs, rhs)
  
          # make sure join keys are in the merged
          # TODO, should _merge_pieces do this?
          for k in by:
              try:
                  if k in merged:
                      merged[k] = key
              except KeyError:
                  pass
  
          pieces.append(merged)
  
      # preserve the original order
      # if we have a missing piece this can be reset
      from pandas.core.reshape.concat import concat
  
      result = concat(pieces, ignore_index=True)
      result = result.reindex(columns=pieces[0].columns, copy=False)
      return result, lby
  
imports: import copy
  import string
  import warnings
  import numpy
  from pandas._libs import hashtable, join, lib
  import pandas.compat
  from pandas.compat import filter, lzip, map, range, zip
  from pandas.errors import MergeError
  from pandas.util._decorators import Appender, Substitution
  from pandas.core.dtypes.common import ensure_float64, ensure_int64, ensure_object, is_array_like, is_bool, is_bool_dtype, is_categorical_dtype, is_datetime64_dtype, is_datetime64tz_dtype, is_datetimelike, is_dtype_equal, is_extension_array_dtype, is_float_dtype, is_int64_dtype, is_integer, is_integer_dtype, is_list_like, is_number, is_numeric_dtype, is_object_dtype, needs_i8_conversion
  from pandas.core.dtypes.missing import isnull, na_value_for_dtype
  from pandas import Categorical, DataFrame, Index, MultiIndex, Series, Timedelta
  import pandas.core.algorithms
  from pandas.core.arrays.categorical import _recode_for_categories
  import pandas.core.common
  from pandas.core.frame import _merge_doc
  from pandas.core.internals import concatenate_block_managers, items_overlap_with_suffix
  import pandas.core.sorting
  from pandas.core.sorting import is_int64_overflow_possible
label_desc: Use image node_id 2 for calling a global function with example usage: _groupby_and_merge(by, on, left, right, _merge_pieces, check_duplicates) and returns: result,  lby