from functools import reduce
import operator


def multidim2cmplist(ar1, ar2, *dim_vals, titles=None):
    """
    Converts a multidimensional array to a list of tuples
    This may be useful for displaying part or all of an array as a
    table or exporting to a pandas dataframe, database or spreadsheet.

    positional arguments
    ar: a multidimensional numpy array
    dim_vals: collections enumerating the basis for each dimension,
        typically the values for a given input in a trial

    keyword arguments
    titles: a list of column titles, each corresponding to a collection
        in dim_vals, except the last which refers to the value.  If the
        last title is omitted, 'value' is used.
    """
    def filled_list(idx):
        """
        adds appropriate copies of a list item based on its index within
        the dim_vals list
        """
        shape = [len(dv) for dv in dim_vals]
        lst = dim_vals[idx]
        pre = shape[:idx]
        post = shape[idx+1:]
        preprod = reduce(operator.mul, pre, 1)
        postprod = reduce(operator.mul, post, 1)
        result = []
        for item in lst:
            result += [item] * postprod
        result *= preprod
        return result

    cols = []
    for i in range(len(dim_vals)):
        cols.append(filled_list(i))
    ar3 = ar1 / ar2
    cols.append(["%1.2e" % v for v in list(ar1.ravel())])
    cols.append(["%1.2e" % v for v in list(ar2.ravel())])
    cols.append(["%1.2e" % v for v in list(ar3.ravel())])
    result = list(zip(*cols))
    if titles:
        if len(titles) == len(result[0]) - 2:
            titles.append('value1', 'value2')
        result.insert(0, tuple(titles))
    return result