Applying a QuickSort algorithm to a table of an atom

All topics on coding 4Dscript in Enterprise Dynamics.
Post Reply
Assil
Posts: 3
Joined: Tuesday 19 April, 2011 - 14:09

Applying a QuickSort algorithm to a table of an atom

Post by Assil »

Say I have atom atmTest which contains two columns. Is it possible to sort the table by using a fast QuickSort algorithm?

Well, there is no builtin, off the shelf, functionality in ED that does this, but you can easily make your own method. Here is the code. The function takes 3 to 4 parameters. The parameters are:
e1: atom contaning the table
e2: the column that
e3: boolean: 1 if ascending, 0 if descending
e4: number of fixed columns that the table contains

QuickSortTable(e1, e2, e3, {e4})

Code: Select all

do(
  var([atmTable], vbAtom, p(1)),
  var([valSortColumn], vbValue, p(2)),
  var([valAscending], vbValue, p(3)),
  var([valSortFixedColumn], vbValue, p(4)),
  var([atmIndexArray], vbAtom),
  var([atmDummyTable], vbAtom),
  var([valColumn], vbValue),
  
  if(
    nRows(atmTable) <= 1,
    return
  ),
  
  {**Create indexed value**}
  atmIndexArray := Array_Create(Model, [IndexArray]),
  atmDummyTable := Array_Create(Model, [DummyArray]),
  Array_SetSize(atmIndexArray, nRows(atmTable)),
  Array_SetSize(atmDummyTable, nRows(atmTable)),
  
  Repeat(
    Array_GetSize(atmIndexArray),
    Array_Set(atmIndexArray, Count, Count)
  ),

  QuickSortIndexed(atmTable, valSortColumn, atmIndexArray, valAscending),

  Repeat(
    nCols(atmTable) + valSortFixedColumn,
    do(  
      valColumn := Count - valSortFixedColumn,
     
      {**Save the array in column count**}
      Repeat(
        nRows(atmTable),
        Cell(Count, 1, atmDummyTable) := Cell(Count, valColumn, atmTable)
      ),
      
      {**Copy it back in rearranged order**}
      Repeat(
        nRows(atmTable),
        Cell(Count, valColumn, atmTable) :=  Cell(Cell(Count, 1, atmIndexArray), 1, atmDummyTable)
      )
    )
  ),  
  
  DestroyAtom(atmIndexArray),
  DestroyAtom(atmDummyTable)
)
The above code makes use of method QuickSortIndexed which is listed here under

QuickSortIndexed(e1, e2, e3, e4)
where
e1: atom contaning the table
e2: the column that
e3: temporary atom where the sorted table is first placed
e4: boolean: 1 if ascending, 0 if descending

Code: Select all

do(
  var([atmTable], vbAtom, p(1)),
  var([valSortColumn], vbValue, p(2)),
  var([atmIndexArray], vbAtom, p(3)),
  var([valAscending], vbValue, p(4)),
  var([valContinue], vbValue, True),
  var([valM], vbValue, 7),
  var([valJStack], vbValue, 0),
  var([valA], vbValue),
  var([valI], vbValue),
  var([valJ], vbValue),
  var([valL], vbValue, 1),
  var([valIR], vbValue, nRows(atmTable)),
  var([valBreak], vbValue),
  var([valK], vbValue),
  var([valIndext], vbValue),
  
  if(
    valAscending,
    
    {**Sort ascending**}
    While(
      valContinue,
      if(
        valIR - valL < valM,
        do(
          For(
            valJ := valL + 1,
            valJ <= valIR,
            inc(valJ),
            do(
              valIndext := Cell(valJ, 1, atmIndexArray),
              valA := Cell(valIndexT, valSortColumn, atmTable),
              valBreak := False,     
              for(
                valI := valJ - 1,
                and(
                  valI >= valL,
                  valBreak = False
                ),
                dec(valI),
                if(
                  Cell(Cell(valI, 1, atmIndexArray), valSortColumn, atmTable) <= valA,
                  do(
                    inc(valI),
                    valBreak := True
                  ),
                  Cell(valI + 1, 1, atmIndexArray) := Cell(valI, 1, atmIndexArray)
                )
              ),      
              Cell(valI + 1, 1, atmIndexArray) := valIndexT      
            )            
          ),
          
          if(
            valJStack = 0,
            valContinue := False,
            do(
              valIR := PopValue,
              valL := PopValue,
              dec(valJstack, 2)
            )
          )
        ),
          
        do(
          valK := Trunc((valL + valIR) / 2), {**Trunc(x/2) is Equal to bitwise left shift with 1**}
          
          {**Swap row k and l + 1**}
          PushValue(Cell(valK, 1, atmIndexArray)),
          Cell(valK, 1, atmIndexArray) := Cell(valL + 1, 1, atmIndexArray),
          Cell(valL + 1, 1, atmIndexArray) := PopValue,
          
          if(
            Cell(Cell(valL, 1, atmIndexArray), valSortColumn, atmTable) > Cell(Cell(valIR, 1, atmIndexArray), valSortColumn, atmTable),
            
            {**Swap row l and ir**}
            do(
              PushValue(Cell(valL, 1, atmIndexArray)),
              Cell(valL, 1, atmIndexArray) := Cell(valIR, 1, atmIndexArray),
              Cell(valIR, 1, atmIndexArray) := PopValue
            )
          ),
          
          if(
            Cell(Cell(valL + 1, 1, atmIndexArray), valSortColumn, atmTable) > Cell(Cell(valIR, 1, atmIndexArray), valSortColumn, atmTable),
            
            {**Swap row l + 1 and ir**}
            do(
              PushValue(Cell(valL + 1, 1, atmIndexArray)),
              Cell(valL + 1, 1, atmIndexArray) := Cell(valIR, 1, atmIndexArray),
              Cell(valIR, 1, atmIndexArray) := PopValue
            )
          ),
          
          if(
            Cell(Cell(valL, 1, atmIndexArray), valSortColumn, atmTable) > Cell(Cell(valL + 1, 1, atmIndexArray), valSortColumn, atmTable),
            
            {**Swap row l and l + 1**}
            do(
              PushValue(Cell(valL, 1, atmIndexArray)),
              Cell(valL, 1, atmIndexArray) := Cell(valL + 1, 1, atmIndexArray),
              Cell(valL + 1, 1, atmIndexArray) := PopValue
            )
          ),
          
          valI := valL + 1,
          valJ := valIR,
          valIndexT := Cell(valL + 1, 1, atmIndexArray),
          valA := Cell(valIndexT, valSortColumn, atmTable),
          
          {**Beginning of innermost loop**}
          valBreak := False,
          LoopUntil(
            valBreak = True,
            do(
              
              {**Scan up to find element > a**}
              inc(valI),
              While(
                and(
                  Cell(Cell(valI, 1, atmIndexArray), valSortColumn, atmTable) < valA,
                  valI <= nRows(atmTable)                
                ),
                inc(valI)
              ),
              
              {**Scan down to find element < a**}
              dec(valJ),
              While(
                and(
                  Cell(Cell(valJ, 1, atmIndexArray), valSortColumn, atmTable) > valA,
                  valJ > 0
                ),
                dec(valJ)
              ),
              
              if(
                valJ < valI,
                valBreak := True,
                
                {**Swap row i and j**}
                do(
                  PushValue(Cell(valI, 1, atmIndexArray)),
                  Cell(valI, 1, atmIndexArray) := Cell(valJ, 1, atmIndexArray),
                  Cell(valJ, 1, atmIndexArray) := PopValue
                )
              )          
            )
          ),  
          
          Cell(valL + 1, 1, atmIndexArray) := Cell(valJ, 1, atmIndexArray),
          Cell(valJ, 1, atmIndexArray) := valIndexT,
          inc(valJstack, 2),        
          
          {**Push pointers to larger subarray on stack, process smaller subarray immediately**}
          if(
            valIR - valI + 1 >= valJ - 1,
            do(
              PushValue(valI),
              PushValue(valIR),
              valIR := valJ - 1
            ),
            do(
              PushValue(valL),
              PushValue(valJ - 1),
              valL := valI           
            )
          )        
        )
      )
    ),
    
    {**Sort Descending**}
    While(
      valContinue,
      if(
        valIR - valL < valM,
        do(
          For(
            valJ := valL + 1,
            valJ <= valIR,
            inc(valJ),
            do(
              valIndext := Cell(valJ, 1, atmIndexArray),
              valA := Cell(valIndext, valSortColumn, atmTable),
              valBreak := False,     
              for(
                valI := valJ - 1,
                and(
                  valI >= valL,
                  valBreak = False
                ),
                dec(valI),
                if(
                  Cell(Cell(valI, 1, atmIndexArray), valSortColumn, atmTable) >= valA,
                  do(
                    inc(valI),
                    valBreak := True
                  ),
                  Cell(valI + 1, 1, atmIndexArray) := Cell(valI, 1, atmIndexArray)
                )
              ),      
              Cell(valI + 1, 1, atmIndexArray) := valIndexT      
            )            
          ),
          
          if(
            valJStack = 0,
            valContinue := False,
            do(
              valIR := PopValue,
              valL := PopValue,
              dec(valJstack, 2)
            )
          )
        ),
          
        do(
          valK := Trunc((valL + valIR) / 2), {**Trunc(x/2) is Equal to bitwise left shift with 1**}
          
          {**Swap row k and l + 1**}
          PushValue(Cell(valK, 1, atmIndexArray)),
          Cell(valK, 1, atmIndexArray) := Cell(valL + 1, 1, atmIndexArray),
          Cell(valL + 1, 1, atmIndexArray) := PopValue,
          
          if(
            Cell(Cell(valL, 1, atmIndexArray), valSortColumn, atmTable) < Cell(Cell(valIR, 1, atmIndexArray), valSortColumn, atmTable),
            
            {**Swap row l and ir**}
            do(
              PushValue(Cell(valL, 1, atmIndexArray)),
              Cell(valL, 1, atmIndexArray) := Cell(valIR, 1, atmIndexArray),
              Cell(valIR, 1, atmIndexArray) := PopValue
            )
          ),
          
          if(
            Cell(Cell(valL + 1, 1, atmIndexArray), valSortColumn, atmTable) < Cell(Cell(valIR, 1, atmIndexArray), valSortColumn, atmTable),
            
            {**Swap row l + 1 and ir**}
            do(
              PushValue(Cell(valL + 1, 1, atmIndexArray)),
              Cell(valL + 1, 1, atmIndexArray) := Cell(valIR, 1, atmIndexArray),
              Cell(valIR, 1, atmIndexArray) := PopValue
            )
          ),
          
          if(
            Cell(Cell(valL, 1, atmIndexArray), valSortColumn, atmTable) < Cell(Cell(valL + 1, 1, atmIndexArray), valSortColumn, atmTable),
            
            {**Swap row l and l + 1**}
            do(
              PushValue(Cell(valL, 1, atmIndexArray)),
              Cell(valL, 1, atmIndexArray) := Cell(valL + 1, 1, atmIndexArray),
              Cell(valL + 1, 1, atmIndexArray) := PopValue
            )
          ),
          
          valI := valL + 1,
          valJ := valIR,
          valIndexT := Cell(valL + 1, 1, atmIndexArray),
          valA := Cell(valIndexT, valSortColumn, atmTable),
          
          {**Beginning of innermost loop**}
          valBreak := False,
          LoopUntil(
            valBreak = True,
            do(
              
              {**Scan up to find element > a**}
              inc(valI),
              While(
                and(
                  Cell(Cell(valI, 1, atmIndexArray), valSortColumn, atmTable) > valA,
                  valI <= nRows(atmTable)                
                ),
                inc(valI)
              ),
              
              {**Scan down to find element < a**}
              dec(valJ),
              While(
                and(
                  Cell(Cell(valJ, 1, atmIndexArray), valSortColumn, atmTable) < valA,
                  valJ > 0
                ),
                dec(valJ)
              ),
              
              if(
                valJ < valI,
                valBreak := True,
                {**Swap row i and j**}
                do(
                  PushValue(Cell(valI, 1, atmIndexArray)),
                  Cell(valI, 1, atmIndexArray) := Cell(valJ, 1, atmIndexArray),
                  Cell(valJ, 1, atmIndexArray) := PopValue
                )
              )          
            )
          ),  
          
          Cell(valL + 1, 1, atmIndexArray) := Cell(valJ, 1, atmIndexArray),
          Cell(valJ, 1, atmIndexArray) := valIndexT,
          inc(valJstack, 2),        
          
          {**Push pointers to larger subarray on stack, process smaller subarray immediately**}
          if(
            valIR - valI + 1 >= valJ - 1,
            do(
              PushValue(valI),
              PushValue(valIR),
              valIR := valJ - 1
            ),
            do(
              PushValue(valL),
              PushValue(valJ - 1),
              valL := valI           
            )
          )        
        )
      )
    )
  )
)
Jeroen
Posts: 9
Joined: Monday 17 January, 2011 - 10:02

Re: Applying a QuickSort algorithm to a table of an atom

Post by Jeroen »

Note that the internal ED command SortTable() also uses quicksort when the 4th parameter (every value is treated as a number) is set to True. For more information see the ED help file.
Post Reply