def _groupby_and_merge(by, on, left, right, _merge_pieces,<EOL>check_duplicates=True):
pieces = []<EOL>if not isinstance(by, (list, tuple)):<EOL><INDENT>by = [by]<EOL><DEDENT>lby = left.groupby(by, sort=False)<EOL>try:<EOL><INDENT>if check_duplicates:<EOL><INDENT>if on is None:<EOL><INDENT>on = []<EOL><DEDENT>elif not isinstance(on, (list, tuple)):<EOL><INDENT>on = [on]<EOL><DEDENT>if right.duplicated(by + on).any():<EOL><INDENT>right = right.drop_duplicates(by + on, keep='<STR_LIT>')<EOL><DEDENT><DEDENT>rby = right.groupby(by, sort=False)<EOL><DEDENT>except KeyError:<EOL><INDENT>rby = None<EOL><DEDENT>for key, lhs in lby:<EOL><INDENT>if rby is None:<EOL><INDENT>rhs = right<EOL><DEDENT>else:<EOL><INDENT>try:<EOL><INDENT>rhs = right.take(rby.indices[key])<EOL><DEDENT>except KeyError:<EOL><INDENT>lcols = lhs.columns.tolist()<EOL>cols = lcols + [r for r in right.columns<EOL>if r not in set(lcols)]<EOL>merged = lhs.reindex(columns=cols)<EOL>merged.index = range(len(merged))<EOL>pieces.append(merged)<EOL>continue<EOL><DEDENT><DEDENT>merged = _merge_pieces(lhs, rhs)<EOL>for k in by:<EOL><INDENT>try:<EOL><INDENT>if k in merged:<EOL><INDENT>merged[k] = key<EOL><DEDENT><DEDENT>except KeyError:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>pieces.append(merged)<EOL><DEDENT>from pandas.core.reshape.concat import concat<EOL>result = concat(pieces, ignore_index=True)<EOL>result = result.reindex(columns=pieces[<NUM_LIT:0>].columns, copy=False)<EOL>return result, lby<EOL>
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