def addcols(X, cols, names=None):
    """
    Add one or more columns to a numpy ndarray.

    Technical dependency of :func:`tabular.spreadsheet.aggregate_in`.

    Implemented by the tabarray method 
    :func:`tabular.tab.tabarray.addcols`.

    **Parameters**

            **X** :  numpy ndarray with structured dtype or recarray

                    The recarray to add columns to.

            **cols** :  numpy ndarray, or list of arrays of columns
            
                    Column(s) to add.

            **names**:  list of strings, optional

                    Names of the new columns. Only applicable when `cols` is a 
                    list of arrays.

    **Returns**

            **out** :  numpy ndarray with structured dtype

                    New numpy array made up of `X` plus the new columns.

    **See also:**  :func:`tabular.spreadsheet.colstack`

    """

    if isinstance(names,str):
        names = [n.strip() for n in names.split(',')]

    if isinstance(cols, list):
        if any([isinstance(x,np.ndarray) or isinstance(x,list) or \
                                     isinstance(x,tuple) for x in cols]):
            assert all([len(x) == len(X) for x in cols]), \
                   'Trying to add columns of wrong length.'
            assert names != None and len(cols) == len(names), \
                   'Number of columns to add must equal number of new names.'
            cols = utils.fromarrays(cols,type=np.ndarray,names = names)
        else:
            assert len(cols) == len(X), 'Trying to add column of wrong length.'
            cols = utils.fromarrays([cols], type=np.ndarray,names=names)
    else:
        assert isinstance(cols, np.ndarray)
        if cols.dtype.names == None:
            cols = utils.fromarrays([cols],type=np.ndarray, names=names)

    Replacements = [a for a in cols.dtype.names if a in X.dtype.names]
    if len(Replacements) > 0:
        print('Replacing columns', 
              [a for a in cols.dtype.names if a in X.dtype.names])

    return utils.fromarrays(
      [X[a] if a not in cols.dtype.names else cols[a] for a in X.dtype.names] + 
      [cols[a] for a in cols.dtype.names if a not in X.dtype.names], 
      type=np.ndarray,
      names=list(X.dtype.names) + [a for a in cols.dtype.names 
                                   if a not in X.dtype.names])
Add one or more columns to a numpy ndarray.

    Technical dependency of :func:`tabular.spreadsheet.aggregate_in`.

    Implemented by the tabarray method 
    :func:`tabular.tab.tabarray.addcols`.

    **Parameters**

            **X** :  numpy ndarray with structured dtype or recarray

                    The recarray to add columns to.

            **cols** :  numpy ndarray, or list of arrays of columns
            
                    Column(s) to add.

            **names**:  list of strings, optional

                    Names of the new columns. Only applicable when `cols` is a 
                    list of arrays.

    **Returns**

            **out** :  numpy ndarray with structured dtype

                    New numpy array made up of `X` plus the new columns.

    **See also:**  :func:`tabular.spreadsheet.colstack`