U
    [eht                     @   s   d Z ddlZddlZddlmZ ddlmZ ddlmZ	 ddlm
Z
 ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ G dd deZdd Zdd ZdddZdd Zdd ZdS )a  
    pyexcel.internal.sheets.matrix
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Matrix, a data model that accepts any types, spread sheet style
    of lookup.

    :copyright: (c) 2014-2022 by Onni Software Ltd.
    :license: New BSD License, see LICENSE for more details
    N)partial)chain)_compact)	constants)	SheetMeta)Row)Column)	to_format)PyexcelList   )_sharedc                   @   sz  e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	d\ddZ
dd Zdd Zd]ddZdd Zdd Zdd Zdd Zd^d d!Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd_d,d-Zd.d/ Zd0d1 Zd2d3 Zd4d5 Zd6d7 Zd8d9 Zd:d; Zd<d= Z d>d? Z!d@dA Z"dBdC Z#dDdE Z$dFdG Z%dHdI Z&dJdK Z'dLdM Z(dNdO Z)d`dPdQZ*dRdS Z+dTdU Z,dVdW Z-dXdY Z.dZd[ Z/dS )aMatrixz]The internal representation of a sheet data. Each element
    can be of any python types
    c                 C   sr   t |tjr"tt|\| _| _n2zt|\| _| _W n tk
rR   tdY nX t| | _	t
| | _d| _dS )zConstructor

        The reason a deep copy was not made here is because
        the data sheet could be huge. It could be costly to
        copy every cell to a new memory area
        :param list array: a list of arrays
        zInvalid two dimensional arraymatrixN)
isinstancetypesGeneratorTypeuniformlist_Matrix__width_Matrix__array	TypeErrorr   rowr   columnname)selfarray r   `/var/www/html/services/stratfitenv/lib/python3.8/site-packages/pyexcel/internal/sheets/matrix.py__init__    s    

zMatrix.__init__c                 C   s   | j S )zpresent internal arrayr   r   r   r   r   get_internal_array3   s    zMatrix.get_internal_arrayc                 C   s
   t | jS )zThe number of rows)lenr   r    r   r   r   number_of_rows7   s    zMatrix.number_of_rowsc                 C   s   |   dkr| jS dS dS )zThe number of columnsr   N)r#   r   r    r   r   r   number_of_columns;   s    zMatrix.number_of_columnsc                 C   s   t |  S )z3
        Utility function to get row range
        )compactiranger#   r    r   r   r   	row_rangeB   s    zMatrix.row_rangec                 C   s   t |  S )z6
        Utility function to get column range
        )r%   r&   r$   r    r   r   r   column_rangeH   s    zMatrix.column_rangeNc                 C   sz   ||   k o||  k }|dkr<|r2| j| | S tdn:|sht| j|d |d \}}|| | _| _|| j| |< dS )zRandom access to table cells

        :param int row: row index which starts from 0
        :param int column: column index which starts from 0
        :param any new_value: new value if this is to set the value
        NzIndex out of ranger   )r#   r$   r   
IndexErrorr   r   )r   r   r   	new_valuefitwidthr   r   r   r   
cell_valueN   s    
zMatrix.cell_valuec                 C   sd   ||   kr tt| j| S |dk rVt||   krVtt| j||    S tt	j
dS )z4
        Gets the data at the specified row
        r   N)r'   r
   copydeepcopyr   utilsabsr#   r)   r   MESSAGE_INDEX_OUT_OF_RANGE)r   indexr   r   r   row_atb   s    zMatrix.row_atc                 C   sL   |   }||k r>|| j|< t||  krHt| j\| _| _n
ttjdS )zUpdate a row data rangeN)	r#   r   r"   r$   r   r   r)   r   r2   )r   	row_index
data_arraynrowsr   r   r   
set_row_atq   s    
zMatrix.set_row_atr   c           
      C   s   |   }|  }||k r||k rt|| }t||}t||D ]}| |||||   q@||kr|| }	| j| ||	d  | j|< t| j\| _| _n
t	t
jdS )aH  Update a row data range

        It works like this if the call is: set_row_at(2, ['N', 'N', 'N'], 1)::

            A B C
            1 3 5
            2 N N <- row_index = 2
              ^starting = 1

        This function will not set element outside the current table range

        :param int row_index: which row to be modified
        :param list data_array: one dimensional array
        :param int starting: from which index, the update happens
        :raises IndexError: if row_index exceeds row range or starting
                            exceeds column range
        N)r#   r$   r"   minranger-   r   r   r   r)   r   r2   )
r   r5   r6   startingr7   ncolumnsreal_lenendileftr   r   r   _set_row_at{   s    
zMatrix._set_row_atc                 C   s6   t |}t|tr&|  j|7  _n| j| d S N)r.   r/   r%   is_array_typer   r   append)r   r   r   r   r   r   _extend_row   s    
zMatrix._extend_rowc                 C   s<   t |tr(| | t| j\| _| _ntdt| dS )z1Inserts two dimensional data after the bottom rowzCannot use %sN)r   r   rE   r   r   r   r   typer   rowsr   r   r   extend_rows   s    

zMatrix.extend_rowsc                 C   s\   t |tdkrtt|dkrXt|}t|dd}|D ] }||  k r6|dkr6| j|= q6dS )zDeletes specified row indicesFr   TreverseN)r   r   r)   r"   _uniquesortedr#   r   )r   row_indicesunique_listsorted_listr?   r   r   r   delete_rows   s    zMatrix.delete_rowsc                 C   s   t  }||  kr6|  D ]}|| || q|S |dk rt||  kr|  | }|  D ]}|| || qd|S tt	j
dS )z7
        Gets the data at the specified column
        r   N)r
   r(   r'   rD   r-   r0   r1   r$   r)   r   r2   )r   r3   Z
cell_arrayr?   Zreverse_indexr   r   r   	column_at   s    zMatrix.column_atc           
      C   s   |   }|  }||k r||k rt|| }t||}t||D ]}| |||||   q@||krt||D ](}dg| |||  g }	| j|	 qnt| j\| _	| _n
t
tjdS )ay  Updates a column data range

        It works like this if the call is:
        set_column_at(2, ['N','N', 'N'], 1)::

                +--> column_index = 2
                |
            A B C
            1 3 N <- starting = 1
            2 4 N

        This function will not set element outside the current table range

        :param int column_index: which column to be modified
        :param list data_array: one dimensional array
        :param int staring: from which index, the update happens
        :raises IndexError: if column_index exceeds column range
                            or starting exceeds row range
         N)r#   r$   r"   r9   r:   r-   r   rD   r   r   r)   r   r2   )
r   column_indexr6   r;   r7   r<   r=   r>   r?   Znew_rowr   r   r   set_column_at   s    
zMatrix.set_column_atc                 C   s@   t |tsttj|}t|ts*|g}t|}| | dS )zInserts two dimensional data after the rightmost column

        This is how it works:

        Given::

            s s s     t t

        Get::

            s s s  +  t t
        N)	r   r   r   r   %MESSAGE_DATA_ERROR_DATA_TYPE_MISMATCHr%   rC   	transpose_extend_columns_with_rows)r   columnsZincoming_datar   r   r   extend_columns   s    

zMatrix.extend_columnsc                 C   s   |   }|  }t|}t||}td|D ]$}t|| }| j|  |7  < q,||k r|| }|}	td|D ],}tj	g| }
|
||	|  7 }
| j
|
 qpt| j\| _| _d S )Nr   )r#   r$   r"   r9   r:   r.   r/   r   r   
DEFAULT_NArD   r   r   )r   rH   Zcurrent_nrowsZcurrent_ncolsZinsert_column_nrowsarray_lengthr?   r   deltabase	new_arrayr   r   r   rX     s    
z Matrix._extend_columns_with_rowsc                 C   s   |  | dS )aK  Rows were appended to the rightmost side

        example::

            >>> import pyexcel as pe
            >>> data = [
            ...     [1],
            ...     [2],
            ...     [3]
            ... ]
            >>> matrix = pe.Sheet(data)
            >>> matrix
            pyexcel sheet:
            +---+
            | 1 |
            +---+
            | 2 |
            +---+
            | 3 |
            +---+
            >>> rows = [
            ...      [11, 11],
            ...      [22, 22]
            ... ]
            >>> matrix.extend_columns_with_rows(rows)
            >>> matrix
            pyexcel sheet:
            +---+----+----+
            | 1 | 11 | 11 |
            +---+----+----+
            | 2 | 22 | 22 |
            +---+----+----+
            | 3 |    |    |
            +---+----+----+
        N)rX   rG   r   r   r   extend_columns_with_rows  s    $zMatrix.extend_columns_with_rowsc           	      C   st   g }t |d |  }t |d |  }t|d |D ]8}g }t|d |D ]}|| || qL|| q6|S )zGet a rectangle shaped data out

        :param slice topleft_corner: the top left corner of the rectangle
        :param slice bottomright_corner: the bottom right
                                         corner of the rectangle
        r   r   )r9   r#   r$   r:   rD   r-   )	r   topleft_cornerbottomright_cornerregionZmax_rowZmax_colr   Ztmp_rowr   r   r   r   rc   9  s    zMatrix.regionc                 C   sP   |  ||}t|d |d D ],}t|d |d D ]}| ||tj q4q|S )a	  Get a rectangle shaped data out and clear them in position

        :param slice topleft_corner: the top left corner of the rectangle
        :param slice bottomright_corner: the bottom right
                                         corner of the rectangle
        r   r   )rc   r:   r-   r   r[   )r   ra   rb   rc   r   r   r   r   r   cutJ  s
    z
Matrix.cutc                 C   s2   |r|  || n|r$| || n
ttjdS )a  Paste a rectangle shaped data after a position

        :param slice topleft_corner: the top left corner of the rectangle

        example::

            >>> import pyexcel as pe
            >>> data = [
            ...     # 0 1  2  3  4 5   6
            ...     [1, 2, 3, 4, 5, 6, 7], #  0
            ...     [21, 22, 23, 24, 25, 26, 27],
            ...     [31, 32, 33, 34, 35, 36, 37],
            ...     [41, 42, 43, 44, 45, 46, 47],
            ...     [51, 52, 53, 54, 55, 56, 57]  # 4
            ... ]
            >>> s = pe.Sheet(data)
            >>> # cut  1<= row < 4, 1<= column < 5
            >>> data = s.cut([1, 1], [4, 5])
            >>> s.paste([4,6], rows=data)
            >>> s
            pyexcel sheet:
            +----+----+----+----+----+----+----+----+----+----+
            | 1  | 2  | 3  | 4  | 5  | 6  | 7  |    |    |    |
            +----+----+----+----+----+----+----+----+----+----+
            | 21 |    |    |    |    | 26 | 27 |    |    |    |
            +----+----+----+----+----+----+----+----+----+----+
            | 31 |    |    |    |    | 36 | 37 |    |    |    |
            +----+----+----+----+----+----+----+----+----+----+
            | 41 |    |    |    |    | 46 | 47 |    |    |    |
            +----+----+----+----+----+----+----+----+----+----+
            | 51 | 52 | 53 | 54 | 55 | 56 | 22 | 23 | 24 | 25 |
            +----+----+----+----+----+----+----+----+----+----+
            |    |    |    |    |    |    | 32 | 33 | 34 | 35 |
            +----+----+----+----+----+----+----+----+----+----+
            |    |    |    |    |    |    | 42 | 43 | 44 | 45 |
            +----+----+----+----+----+----+----+----+----+----+
            >>> s.paste([6,9], columns=data)
            >>> s
            pyexcel sheet:
            +----+----+----+----+----+----+----+----+----+----+----+----+
            | 1  | 2  | 3  | 4  | 5  | 6  | 7  |    |    |    |    |    |
            +----+----+----+----+----+----+----+----+----+----+----+----+
            | 21 |    |    |    |    | 26 | 27 |    |    |    |    |    |
            +----+----+----+----+----+----+----+----+----+----+----+----+
            | 31 |    |    |    |    | 36 | 37 |    |    |    |    |    |
            +----+----+----+----+----+----+----+----+----+----+----+----+
            | 41 |    |    |    |    | 46 | 47 |    |    |    |    |    |
            +----+----+----+----+----+----+----+----+----+----+----+----+
            | 51 | 52 | 53 | 54 | 55 | 56 | 22 | 23 | 24 | 25 |    |    |
            +----+----+----+----+----+----+----+----+----+----+----+----+
            |    |    |    |    |    |    | 32 | 33 | 34 | 35 |    |    |
            +----+----+----+----+----+----+----+----+----+----+----+----+
            |    |    |    |    |    |    | 42 | 43 | 44 | 22 | 32 | 42 |
            +----+----+----+----+----+----+----+----+----+----+----+----+
            |    |    |    |    |    |    |    |    |    | 23 | 33 | 43 |
            +----+----+----+----+----+----+----+----+----+----+----+----+
            |    |    |    |    |    |    |    |    |    | 24 | 34 | 44 |
            +----+----+----+----+----+----+----+----+----+----+----+----+
            |    |    |    |    |    |    |    |    |    | 25 | 35 | 45 |
            +----+----+----+----+----+----+----+----+----+----+----+----+

        N)_paste_rows_paste_columns
ValueErrorr   Z MESSAGE_DATA_ERROR_EMPTY_CONTENT)r   ra   rH   rY   r   r   r   pasteW  s
    ?zMatrix.pastec                    s   |\}}|   }|  }|| }|dkrTt||  fddt|D }| | |   }t|D ]L\}	}
||	 }||k r| j||
|d d qdtj	g|d  |
 }| | qdt
| j\| _| _d S )Nr   c                    s    g | ]}d d t  D qS )c                 S   s   g | ]
}t jqS r   )r   r[   ).0_r   r   r   
<listcomp>  s     z1Matrix._paste_rows.<locals>.<listcomp>.<listcomp>)r%   r&   )ri   __Zmax_columnsr   r   rk     s   z&Matrix._paste_rows.<locals>.<listcomp>r   r;   )r#   r$   maxr%   r&   rE   	enumeraterA   r   r[   r   r   r   )r   ra   rH   Zstarting_rowstarting_columnr#   r$   r]   Z	empty_rowr3   r   	set_indexZreal_rowr   rm   r   re     s$    


zMatrix._paste_rowsc           	      C   s   |d }|   }t|D ]R\}}|| }||k rF| j|||d d qtjg|d  }||7 }| |g qt| j\| _| _d S )Nr   r   rn   )	r$   rp   rU   r   r[   rZ   r   r   r   )	r   ra   rY   rq   r$   r3   r   rr   Zreal_columnr   r   r   rf     s      zMatrix._paste_columnsc                 C   s   t |tdkrttjt|dkr|t|}t|dd}|  D ].}|D ]$}|| 	 k rH|dkrH| j
| |= qHq@t| j
| _dS )z+Delete columns by specified list of indicesFr   TrJ   N)r   r   r   r   rV   r"   rL   rM   r'   r$   r   longest_row_numberr   )r   column_indicesrO   rP   r?   jr   r   r   delete_columns  s    
zMatrix.delete_columnsc                 C   sN   t |tr | |d |d |S t |trFt|\}}| |||S tdS )z"Override the operator to set itemsr   r   N)r   tupler-   strr0   excel_cell_positionr)   )r   asetr-   r   r   r   r   r   __setitem__  s    

zMatrix.__setitem__c                 C   sh   t |tr| |d |d S t |trBt|\}}| ||S t |tr`ttj	 | 
|S tdS )zNBy default, this class recognize from top to bottom
        from left to rightr   r   N)r   rw   r-   rx   r0   ry   intprintr   ZMESSAGE_DEPRECATED_ROW_COLUMNr4   r)   )r   rz   r   r   r   r   r   __getitem__  s    




zMatrix.__getitem__c                 C   s    |   D ]}||r dS qdS )zHas something in the tableTFrH   )r   	predicater   r   r   r   contains  s    zMatrix.containsc                 C   s"   t | j| _t| j\| _| _dS )zQRotate the data table by 90 degrees

        Reference :func:`transpose`
        N)rW   r   r   r   r    r   r   r   rW     s    zMatrix.transposec                 C   s   | j S )zGet an array outr   r    r   r   r   to_array  s    zMatrix.to_arrayc                 C   s   |   S )z
        Default iterator to go through each cell one by one from top row to
        bottom row and from left to right
        r   r    r   r   r   __iter__  s    zMatrix.__iter__c                 C   s
   t | j S )a  
        Iterate cell by cell from top to bottom and from left to right

        .. testcode::

            >>> import pyexcel as pe
            >>> data = [
            ...     [1, 2, 3, 4],
            ...     [5, 6, 7, 8],
            ...     [9, 10, 11, 12]
            ... ]
            >>> m = pe.internal.sheets.Matrix(data)
            >>> print(list(m.enumerate()))
            [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

        More details see :class:`HTLBRIterator`
        )r   r   r    r   r   r   rp     s    zMatrix.enumeratec                 c   s(   t | jD ]}t |D ]
}|V  qq
dS )a  Opposite to enumerate

        each cell one by one from
        bottom row to top row and from right to left
        example::

            >>> import pyexcel as pe
            >>> data = [
            ...     [1, 2, 3, 4],
            ...     [5, 6, 7, 8],
            ...     [9, 10, 11, 12]
            ... ]
            >>> m = pe.internal.sheets.Matrix(data)
            >>> print(list(m.reverse()))
            [12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

        More details see :class:`HBRTLIterator`
        Nreversedr   )r   r   cellr   r   r   rK     s    zMatrix.reversec                 C   s   t tj| j  S )a  
        Default iterator to go through each cell one by one from
        leftmost column to rightmost row and from top to bottom
        example::

            import pyexcel as pe
            data = [
                [1, 2, 3, 4],
                [5, 6, 7, 8],
                [9, 10, 11, 12]
            ]
            m = pe.internal.sheets.Matrix(data)
            print(list(m.vertical()))

        output::

            [1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12]

        More details see :class:`VTLBRIterator`
        )r   r%   czipr   r    r   r   r   vertical,  s    zMatrix.verticalc                 c   s4   t jdd | jD  D ]}t|D ]
}|V  q"qdS )a  
        Default iterator to go through each cell one by one from rightmost
        column to leftmost row and from bottom to top
        example::

            import pyexcel as pe
            data = [
                [1, 2, 3, 4],
                [5, 6, 7, 8],
                [9, 10, 11, 12]
            ]
            m = pe.internal.sheets.Matrix(data)
            print(pe.utils.to_array(m.rvertical())

        output::

            [12, 8, 4, 11, 7, 3, 10, 6, 2, 9, 5, 1]

        More details see :class:`VBRTLIterator`
        c                 s   s   | ]}t |V  qd S rB   r   ri   r   r   r   r   	<genexpr>X  s     z#Matrix.rvertical.<locals>.<genexpr>N)r%   r   r   r   )r   r   r   r   r   r   	rverticalC  s    zMatrix.rverticalc                 c   s   | j D ]
}|V  qdS )a  
        Returns a top to bottom row iterator

        example::

            import pyexcel as pe
            data = [
                [1, 2, 3, 4],
                [5, 6, 7, 8],
                [9, 10, 11, 12]
            ]
            m = pe.internal.sheets.Matrix(data)
            print(pe.utils.to_array(m.rows()))

        output::

            [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]

        More details see :class:`RowIterator`
        Nr   r   r   r   r   r   rH   \  s    
zMatrix.rowsc                 c   s   t | jD ]
}|V  q
dS )a  
        Returns a bottom to top row iterator

        .. testcode::

            import pyexcel as pe
            data = [
                [1, 2, 3, 4],
                [5, 6, 7, 8],
                [9, 10, 11, 12]
            ]
            m = pe.internal.sheets.Matrix(data)
            print(pe.utils.to_array(m.rrows()))

        .. testoutput::

            [[9, 10, 11, 12], [5, 6, 7, 8], [1, 2, 3, 4]]

        More details see :class:`RowReverseIterator`
        Nr   r   r   r   r   rrowst  s    zMatrix.rrowsc                 c   s    t j| j D ]}t|V  qdS )a  
        Returns a left to right column iterator

        .. testcode::

            import pyexcel as pe
            data = [
                [1, 2, 3, 4],
                [5, 6, 7, 8],
                [9, 10, 11, 12]
            ]
            m = pe.internal.sheets.Matrix(data)
            print(list(m.columns()))

        .. testoutput::

            [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

        More details see :class:`ColumnIterator`
        Nr%   r   r   r   r   r   r   r   rY     s    zMatrix.columnsc                 c   s*   t jdd | jD  D ]}t|V  qdS )a  
        Returns a right to left column iterator

        example::

            import pyexcel as pe
            data = [
                [1, 2, 3, 4],
                [5, 6, 7, 8],
                [9, 10, 11, 12]
            ]
            m = pe.internal.sheets.Matrix(data)
            print(pe.utils.to_array(m.rcolumns()))

        output::

            [[4, 8, 12], [3, 7, 11], [2, 6, 10], [1, 5, 9]]

        More details see :class:`ColumnReverseIterator`
        c                 s   s   | ]}t |V  qd S rB   r   r   r   r   r   r     s     z"Matrix.rcolumns.<locals>.<genexpr>Nr   )r   r   r   r   r   rcolumns  s    zMatrix.rcolumnsc                 C   s(   |dk	r|  | |dk	r$| | dS )z&Apply the filter with immediate effectN)rQ   rv   )r   rt   rN   r   r   r   filter  s    
zMatrix.filterc                 C   s   t t|}| | dS )a  Apply a formatting action for the whole sheet

        Example::

            >>> import pyexcel as pe
            >>> # Given a dictinoary as the following
            >>> data = {
            ...     "1": [1, 2, 3, 4, 5, 6, 7, 8],
            ...     "3": [1.25, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8],
            ...     "5": [2, 3, 4, 5, 6, 7, 8, 9],
            ...     "7": [1, '',]
            ...     }
            >>> sheet = pe.get_sheet(adict=data)
            >>> sheet.row[1]
            [1, 1.25, 2, 1]
            >>> sheet.format(str)
            >>> sheet.row[1]
            ['1', '1.25', '2', '1']
            >>> sheet.format(int)
            >>> sheet.row[1]
            [1, 1, 2, 1]

        N)r   r	   map)r   	formattercustom_functionr   r   r   format  s    
zMatrix.formatc                 C   sB   |   D ]4}|  D ]&}| ||}||}| ||| qqdS )a  Execute a function across all cells of the sheet

        Example::

            >>> import pyexcel as pe
            >>> # Given a dictinoary as the following
            >>> data = {
            ...     "1": [1, 2, 3, 4, 5, 6, 7, 8],
            ...     "3": [1.25, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8],
            ...     "5": [2, 3, 4, 5, 6, 7, 8, 9],
            ...     "7": [1, '',]
            ...     }
            >>> sheet = pe.get_sheet(adict=data)
            >>> sheet.row[1]
            [1, 1.25, 2, 1]
            >>> inc = lambda value: (float(value) if value != '' else 0)+1
            >>> sheet.map(inc)
            >>> sheet.row[1]
            [2.0, 2.25, 3.0, 2.0]

        N)r'   r(   r-   )r   r   r   r   valuer   r   r   r     s
    z
Matrix.mapc                 C   s   t | j| j|S rB   )_addr   r   r   otherr   r   r   __iadd__  s    zMatrix.__iadd__c                 C   s   t | jt| j|S )z:Overload the + sign

        :returns: a new book
        )r   r   r.   r/   r   r   r   r   r   __add__  s    zMatrix.__add__c                 C   s   t t| jS rB   )r   r.   r/   r   r    r   r   r   clone  s    zMatrix.clone)N)r   )r   )NN)NN)0__name__
__module____qualname____doc__r   r!   r#   r$   r'   r(   r-   r4   r8   rA   rE   rI   rQ   rR   rU   rZ   rX   r`   rc   rd   rh   re   rf   rv   r{   r~   r   rW   r   r   rp   rK   r   r   rH   r   rY   r   r   r   r   r   r   r   r   r   r   r   r      sZ   


"
#&
F

r   c                    s    t    j fdd| D S )zReturn a unique list of the incoming list

    Reference:
    http://stackoverflow.com/questions/480214/
    how-do-you-remove-duplicates-from-a-list-in-python-whilst-preserving-order
    c                    s    g | ]}| ks|s|qS r   r   )ri   xseenZseen_addr   r   rk     s       z_unique.<locals>.<listcomp>)setadd)seqr   r   r   rL     s    rL   c                 C   s"   t | dkrttt | S dS dS )z`Find the length of the longest row in the array

    :param list in_array: a list of arrays
    r   N)r"   ro   r   )r   r   r   r   rs     s    rs   c           
      C   s   t |t| }t| }t ||}|dkr0d| fS | D ]N}t|}td|D ]}|| dkrJtj||< qJ||k r4|tjg||  7 }q4t||D ]}	tjg| }| | q|| fS dS )zFill-in empty strings to empty cells to make it MxN

    :param list in_array: a list of arrays
    :param int row_no: desired minimum row count
    :param int column_no: desired minimum column length
    r   N)ro   rs   r"   r:   r   r[   rD   )
r   Zmin_rowsZmin_columnsr,   r\   heightr   Z
row_lengthr3   rj   r   r   r   r      s     
r   c                 C   s`   t | }g }td|D ]D}g }| D ],}|t|k rB|||  q"|tj q"|| q|S )a
  Rotate clockwise by 90 degrees and flip horizontally

    First column become first row.
    :param list in_array: a list of arrays

    The transformation is::

        1 2 3       1  4
        4 5 6 7 ->  2  5
                    3  6
                    '' 7
    r   )rs   r:   r"   rD   r   r[   )Zin_array
max_lengthr_   r?   Zrow_datar   r   r   r   rW   ;  s    rW   c                 C   s   ddl m}m} i }||| < t||rt| }| D ]D}|}t| dkrZ|j	}||krt| }	d||	f }|| ||< q<nDt|t
r|j}||kr| }	d|j|	f }t| ||< nt| }
|
| |
S )Nr   )Book
local_uuidr   z%s_%s)Zpyexcel.bookr   r   r   r.   r/   to_dictkeysr"   filenamer   r   r!   r   Zload_from_sheets)r   r@   rightr   r   contentZright_in_dictkeyZnew_keyuidZnew_bookr   r   r   r   U  s.    


r   )r   r   )r   r.   r   	functoolsr   	itertoolsr   Zpyexcelr   r%   r   Zpyexcel.internal.metar   Zpyexcel.internal.sheets.rowr   Zpyexcel.internal.sheets.columnr   Z"pyexcel.internal.sheets.formattersr	   Z%pyexcel.internal.sheets.extended_listr
   rS   r   r0   r   rL   rs   r   rW   r   r   r   r   r   <module>   s.   
     r
