Horizontally stack a sequence of numpy ndarrays with structured dtypes

    Analog of numpy.hstack for recarrays.

    Implemented by the tabarray method 
    :func:`tabular.tab.tabarray.colstack` which uses 
    :func:`tabular.tabarray.tab_colstack`.

    **Parameters**

            **seq** :  sequence of numpy ndarray with structured dtype

                    List, tuple, etc. of numpy recarrays to stack vertically.

            **mode** :  string in ['first','drop','abort','rename']

                    Denotes how to proceed if when multiple recarrays share the 
                    same column name:

                    *   if `mode` == ``first``, take the column from the first
                        recarray in `seq` containing the shared column name.

                    *   elif `mode` == ``abort``, raise an error when the 
                        recarrays to stack share column names; this is the
                        default mode.

                    *   elif `mode` == ``drop``, drop any column that shares    
                        its name with any other column among the sequence of 
                        recarrays.

                    *   elif `mode` == ``rename``, for any set of all columns
                        sharing the same name, rename all columns by appending 
                        an underscore, '_', followed by an integer, starting 
                        with '0' and incrementing by 1 for each subsequent 
                        column.

    **Returns**

            **out** :  numpy ndarray with structured dtype

                    Result of horizontally stacking the arrays in `seq`.

    **See also:**  `numpy.hstack 
    <http://docs.scipy.org/doc/numpy/reference/generated/numpy.hstack.html>`_.

def colstack(seq, mode='abort',returnnaming=False):
    """
    Horizontally stack a sequence of numpy ndarrays with structured dtypes

    Analog of numpy.hstack for recarrays.

    Implemented by the tabarray method 
    :func:`tabular.tab.tabarray.colstack` which uses 
    :func:`tabular.tabarray.tab_colstack`.

    **Parameters**

            **seq** :  sequence of numpy ndarray with structured dtype

                    List, tuple, etc. of numpy recarrays to stack vertically.

            **mode** :  string in ['first','drop','abort','rename']

                    Denotes how to proceed if when multiple recarrays share the 
                    same column name:

                    *   if `mode` == ``first``, take the column from the first
                        recarray in `seq` containing the shared column name.

                    *   elif `mode` == ``abort``, raise an error when the 
                        recarrays to stack share column names; this is the
                        default mode.

                    *   elif `mode` == ``drop``, drop any column that shares    
                        its name with any other column among the sequence of 
                        recarrays.

                    *   elif `mode` == ``rename``, for any set of all columns
                        sharing the same name, rename all columns by appending 
                        an underscore, '_', followed by an integer, starting 
                        with '0' and incrementing by 1 for each subsequent 
                        column.

    **Returns**

            **out** :  numpy ndarray with structured dtype

                    Result of horizontally stacking the arrays in `seq`.

    **See also:**  `numpy.hstack 
    <http://docs.scipy.org/doc/numpy/reference/generated/numpy.hstack.html>`_.

    """
    assert mode in ['first','drop','abort','rename'], \
       'mode argument must take on value "first","drop", "rename", or "abort".'

    AllNames = utils.uniqify(utils.listunion(
                                           [list(l.dtype.names) for l in seq]))
    NameList = [(x, [i for i in range(len(seq)) if x in seq[i].dtype.names]) 
                     for x in AllNames]
    Commons = [x[0] for x in NameList if len(x[1]) > 1]

    if len(Commons) > 0 or mode == 'first':
        if mode == 'abort':
            raise ValueError('There are common column names with differing ' +              
                             'values in the columns')
        elif mode == 'drop':
            Names = [(L[0], x,x) for (x, L) in NameList if x not in Commons]
        elif mode == 'rename':
            NameDict = dict(NameList)
            Names = utils.listunion([[(i,n,n) if len(NameDict[n]) == 1 else \
               (i,n,n + '_' + str(i)) for n in s.dtype.names] \
                                   for (i,s) in enumerate(seq)])                           
    else:
        Names = [(L[0], x,x) for (x, L) in NameList]
    
    if returnnaming:
        return  utils.fromarrays([seq[i][x] for (i, x,y) in Names], 
                 type= np.ndarray,names=zip(*Names)[2]),Names
    else:
        return utils.fromarrays([seq[i][x] for (i, x,y) in Names], 
                 type= np.ndarray,names=zip(*Names)[2])