def join(L, keycols=None, nullvals=None, renamer=None, <EOL>returnrenaming=False, Names=None):
if isinstance(L, dict):<EOL><INDENT>Names = list(L.keys())<EOL>LL = list(L.values())<EOL><DEDENT>else:<EOL><INDENT>if Names == None:<EOL><INDENT>Names = list(range(len(L)))<EOL><DEDENT>else:<EOL><INDENT>assert len(Names) == len(L)<EOL><DEDENT>LL = L<EOL><DEDENT>if not keycols:<EOL><INDENT>keycols = utils.listintersection([a.dtype.names for a in LL])<EOL>if len(keycols) == <NUM_LIT:0>:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>keycols = [l for l in keycols if all([a.dtype[l] == LL[<NUM_LIT:0>].dtype[l] <EOL>for a in LL])]<EOL>if len(keycols) == <NUM_LIT:0>:<EOL><INDENT>raise ValueError('<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT>keycols = [l for l in keycols if all([isunique(a[keycols]) <EOL>for a in LL])]<EOL>if len(keycols) == <NUM_LIT:0>:<EOL><INDENT>raise ValueError('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>print(('<STR_LIT>', keycols))<EOL><DEDENT><DEDENT>elif isinstance(keycols,str):<EOL><INDENT>keycols = [l.strip() for l in keycols.split('<STR_LIT:U+002C>')]<EOL><DEDENT>commons = set(Commons([l.dtype.names for l in LL])).difference(keycols)<EOL>renaming = {}<EOL>if len(commons) > <NUM_LIT:0>:<EOL><INDENT>print('<STR_LIT>')<EOL>if renamer == None:<EOL><INDENT>print('<STR_LIT>')<EOL>renamer = DEFAULT_RENAMER<EOL><DEDENT>renaming = renamer(L, Names=Names)<EOL>if not RenamingIsInCorrectFormat(renaming, L, Names=Names):<EOL><INDENT>print('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>renaming = DEFAULT_RENAMER(L, Names = Names)<EOL><DEDENT>NewNames = [[l if l not in list(renaming[k].keys()) else renaming[k][l] <EOL>for l in ll.dtype.names] for (k, ll) in zip(Names, LL)]<EOL>if set(Commons(NewNames)).difference(keycols):<EOL><INDENT>raise ValueError('<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT><DEDENT>Result = strictjoin(L, keycols, nullvals, renaming, Names=Names)<EOL>if returnrenaming:<EOL><INDENT>return [Result, renaming]<EOL><DEDENT>else:<EOL><INDENT>if renaming:<EOL><INDENT>print('<STR_LIT>'      <EOL>'<STR_LIT>')<EOL><DEDENT>return Result<EOL><DEDENT>
Combine two or more numpy ndarray with structured dtype on common key 
column(s).

Merge a list (or dictionary) of numpy ndarray with structured dtype, given
by `L`, on key columns listed in `keycols`.

This function is actually a wrapper for 
:func:`tabular.spreadsheet.strictjoin`.

The ``strictjoin`` function has a few restrictions, and this ``join``
function will try to ensure that they are satisfied:

*   each element of `keycol` must be a valid column name in `X`
    and each array in `L`, and all of the same data-type.

*   for each column `col`  in `keycols`, and each array `A` in `L`, the 
    values in `A[col]` must be unique, -- and same for `X[col]`.  
    (Actually this uniqueness doesn't have to hold for the first tabarray
    in L, that is, L[0], but must for all the subsequent ones.)

*   the *non*-key-column column names in each of the arrays must be 
    disjoint from each other -- or disjoint after a renaming (see below).

An error will be thrown if these conditions are not met.

If you don't provide a value of `keycols`, the algorithm will attempt to 
infer which columns should be used by trying to find the largest set of 
common column names that contain unique values in each array and have the 
same data type.  An error will be thrown if no such inference can be made.

*Renaming of overlapping columns*

        If the non-keycol column names of the arrays overlap, ``join`` will 
        by default attempt to rename the columns by using a simple 
        convention:

        *   If `L` is a list, it will append the number in the list to the 
            key associated with the array.

        *   If `L` is a dictionary, the algorithm will append the string 
            representation of the key associated with an array to the 
            overlapping columns from that array.

        You can override the default renaming scheme using the `renamer` 
        parameter.

*Nullvalues for keycolumn differences*

        If there are regions of the keycolumns that are not overlapping 
        between merged arrays, `join` will fill in the relevant entries 
        with null values chosen by default:

        *   '0' for integer columns

        *   '0.0' for float columns

        *   the empty character ('') for string columns.

**Parameters**

        **L** :  list or dictionary

                Numpy recarrays to merge.  If `L` is a dictionary, the keys
                name each numpy recarray, and the corresponding values are 
                the actual numpy recarrays.

        **keycols** :  list of strings

                List of the names of the key columns along which to do the 
                merging.

        **nullvals** :  function, optional

                A function that returns a null value for a numpy format
                descriptor string, e.g. ``'<i4'`` or ``'|S5'``.

                See the default function for further documentation:

                        :func:`tabular.spreadsheet.DEFAULT_NULLVALUEFORMAT`

        **renamer** :  function, optional

                A function for renaming overlapping non-key column names 
                among the numpy recarrays to merge.

                See the default function for further documentation:

                        :func:`tabular.spreadsheet.DEFAULT_RENAMER`

        **returnrenaming** :  Boolean, optional

                Whether to return the result of the `renamer` function.

                See the default function for further documentation:

                        :func:`tabular.spreadsheet.DEFAULT_RENAMER`

        **Names**: list of strings:

                If `L` is a list, than names for elements of `L` can be 
                specified with `Names` (without losing the ordering as you 
                would if you did it with a dictionary).  

                `len(L)` must equal `len(Names)`

**Returns**

        **result** :  numpy ndarray with structured dtype

                Result of the join, e.g. the result of merging the input
                numpy arrays defined in `L` on the key columns listed in 
                `keycols`.

        **renaming** :  dictionary of dictionaries, optional

                The result returned by the `renamer` function. Returned 
                only if `returnrenaming == True`.

                See the default function for further documentation:

                        :func:`tabular.spreadsheet.DEFAULT_RENAMER`

**See Also:**

        :func:`tabular.spreadsheet.strictjoin`