Search code examples
performanceemeditor

Optimised Function to copy columns of selected data by a variable amount (up/down)


Is it possible to create a javascript function that can be used in macros, that can move data by an amount when moving columns of data by variable rows. For example, by passing a parameter (iRow?) to something like setcolumn and it would insert the data either above (-1 to lose the first value and then insert which is like moving the column data up one line up for example) or +2 (to blank the first 2 rows column data and then paste the rest of the data, which is like moving it down 2 columns?

Ideally optimised for speed when working on very large amounts of data (millions of rows). Couple of examples. Col1 is source data, Col2 is copying that column and moving up by one row (-1). Col3 is copying that initial col and moving down by two (+2):

Data Data-1 Data+2
00000001 00000002
00000002 00000003
00000003 00000004 00000001
00000004 00000005 00000002
00000005 00000006 00000003
00000006 00000007 00000004
00000007 00000008 00000005
00000008 00000009 00000006
00000009 00000010 00000007
00000010 00000008

Solution

  • I wrote a JavaScript for EmEditor macro. MoveCells( -1, true ) copies the selected cells up to right, and MoveCells( 1, false ) moves the selected cells down.

    // yShift : Specify how many rows to shift (move) the cell selection ( >0 : down, <0 : up )
    function MoveCells( yShift, bCopy )
    {
        if( !yShift || yShift == 0 ) {
            Quit();
        }
        if( !document.CellMode ) {   // Must be cell selection mode
            alert( "Cell selection mode must be turned on" );
            Quit();
        }
    
        xTop = document.selection.GetTopPointX(eePosCellLogical);
        yTop = document.selection.GetTopPointY(eePosCellLogical);
        xBottom = document.selection.GetBottomPointX(eePosCellLogical);
        yBottom = document.selection.GetBottomPointY(eePosCellLogical);
    
        yLines = document.GetLines();   // retrieve the number of lines
        if( document.GetLine( yLines ).length == 0 ) {  // -1 if the last line is empty
            --yLines;
        }
    
        if( yTop < 0 || xTop < 0 || xBottom < 0 || yBottom < 0 ) {
            alert( "Incorrect selection" );
            Quit();
        }
        if( xTop != xBottom ) {
            alert( "More than one columns are selected" );
            Quit();
        }
    
        bOldRedraw = Redraw;
        Redraw = false;
        bOldCombineHistory = CombineHistory;
        CombineHistory = false;
        yFirstLine = document.HeadingLines + 1;
        if( (yShift < 0 && yTop + yShift < yFirstLine) || (yShift > 0 && yBottom + yShift > yLines) ) {
            if( yShift < 0 ) {
                document.selection.SetActivePoint( eePosCellLogical, xTop, yFirstLine );  // move to the first line
                nCount = yFirstLine - (yTop + yShift);
                for( i = 0; i < nCount; ++i ) {
                    document.selection.LineOpen(true);
                }
                yTop += nCount;
                yBottom += nCount;
            }
            else {
                document.selection.SetActivePoint( eePosCellLogical, xTop, yLines );  // move to the first line
                nCount = yBottom + yShift - yLines;
                for( i = 0; i < nCount; ++i ) {
                    document.selection.LineOpen(false);
                }
            }
        }
    
        sDelimiter = document.Csv.Delimiter;  // retrieve the delimiter
        str = document.GetColumn( xTop, sDelimiter, eeCellIncludeQuotes, yTop, yBottom - yTop + 1 );  // get cell selections from top to bottom, separated by delimiter
    
        if( bCopy ) {
            ++xTop
            document.InsertColumn( xTop );
        }
    
        if( yShift > 0 ) {  // shift down
            for( i = 0; i < yShift; ++i ) {  // insert delimiters before the copied string
                str = sDelimiter + str;
            }
            document.SetColumn( xTop, str, sDelimiter, eeDontQuote, yTop );
        }
        else {              // shift up
            for( i = 0; i < -yShift; ++i ) {  // add delimiters to the copied string
                str += sDelimiter;
            }
            document.SetColumn( xTop, str, sDelimiter, eeDontQuote, yTop + yShift );
        }
    
        document.selection.SetActivePoint( eePosCellLogical, xTop, yTop + yShift );  // move the current selection
        document.selection.SetActivePoint( eePosCellLogical, xTop, yBottom + yShift, true );
    
        Redraw = bOldRedraw;
        CombineHistory = bOldCombineHistory;
    }
    
    // Here is the main code
    MoveCells( -1, true );  // Copy the selection up to right
    MoveCells( 2, false );  // Move the selection down
    

    To run this, save this code as, for instance, Macro.jsee, and then select this file from Select... in the Macros menu. Finally, select Run Macro.jsee in the Macros menu while the current CSV document is active.

    References: