• JavaScript: Sorting a Multidimensional Array — quicksort

    I wrote the following script as an answer to this thread. The goal was to sort a bi-dimensional array.

    The structure of the array is as follows:
    Code:
    row | col. 1 | col. 2
    ---------------------
     0  |   3    | Kevin
     1  |   3    | Alice
     2  |   2    | Steve
     3  |   1    | Adam
     4  |   2    | Sammy
    and the JavaScript code resembles this:
    Code:
    var array = new Array();
    
    array[0] = new Array ( 3, "Kevin" );
    array[1] = new Array ( 3, "Alice" );
    array[2] = new Array ( 2, "Steve" );
    array[3] = new Array ( 1, "Adam"  );
    array[4] = new Array ( 2, "Sammy" );
    The sorted array should be:

    1,Adam
    2,Sammy
    2,Steve
    3,Alice
    3,Kevin

    As you can see, the array should be sorted by considering the 1st column values, and when two values are equal those two rows should be sorted considering the 2nd column.

    I elected the quicksort algorithm to sort the array. Like its name says, the quicksort algorithm is usually the fastest. Its only downside is that when the array was already sorted it will waste more time than other, otherwise slower, algos. Here is the code I used. This version was improved from the version I posted in the original thread, as explained below. The main function, qsort is an adapted version of the classic quicksort. It was ported to JavaScript and modified to use a compare function instead of directly comparing elements with "<" and ">".
    Code:
    function compare ( array, left, right ) {
    
        var depth = 0;
    
        
    while ( depth < array[left].length && depth < array[right].length ) {
    
    	
    	if ( array[left][depth] < array[right][depth] )
    	    return 1;
    	else if ( array[left][depth] > array[right][depth] )
    	    return -1;
    	
    	depth++;	    
    
        }
    
        return 0;
    
    }
    
    
    function qsort ( array, lo, hi ) {
    
      var low  = lo;
      var high = hi;
      mid = Math.floor( (low+high)/2 );
    
      do {
        while ( compare(array, low,  mid) > 0 )
          low++;
    
        while ( compare(array, high, mid) < 0 )
          high--;
    
        if ( low <= high ) {
          swap( array, low, high );
          low++;
          high--;
        }
    
      } while ( low <= high );
    
      if ( high > lo )
        qsort( array, lo, high );
    
      if ( low < hi )
        qsort( array, low, hi );
    
    }
    
    function swap ( a, i, j ) {
    
      var tmp = a[i]; 
      a[i] = a[j];
      a[j] = tmp;
    
    }
    
    
    var array = new Array();
    
    array[0] = new Array ( 3, "Kevin" );
    array[1] = new Array ( 3, "Alice" );
    array[2] = new Array ( 2, "Steve" );
    array[3] = new Array ( 1, "Adam"  );
    array[4] = new Array ( 2, "Sammy" );
    
    qsort ( array, 0, array.length-1 );
    I will not explain the gory details of the quicksort algorithm, others have already done that. This page, for instance, explains it quite well and has a nice Java animation that shows clearly how the algo works. The only difference between their version and mine is that they use the first element as the pivot, while mine uses the middle element (mid = (low+high)/2 - to port to JavaScript we need to use Math.floor() because JS doesn't do integer division)

    We need not understand fully the quicksort algorithm here to understand how the sorting works for our bidimensional array. The trick is that it uses the compare function to determine if a given row is above or underneath another given row in the array. The compare function compares the 1st elements in the 2 given rows, and returns 1 or -1 depending on which is greater. If the two are equal, it moves to the second column. It will continue that way until it reaches the end of the rows, in which case it concludes that the two rows are equal. This is an improvement from the original version, in which only the first two columns were compared.

    Note that the above script can only compare two arguments which can be compared with the "<" and ">" operators. In JavaScript, both numbers and strings can be compared that way, but not your own objects, so be careful.

    That's pretty much it for my explanations, please give me feedback or post any questions you might have as I know I am not very good at giving explanations.

    ciao,
    Scum

    I have corrected an error in the above code, in the compare function...

    Here are a few simplified instructions for anyone who would want to use this code but who's not interested in how it works:

    1/ Copy the three functions and put them at the top of your script.

    2/ Build your array of arrays, in any way you wish (see example above)

    3/ Call qsort(array, 0, array.length-1);

    that's it!

    Please report any errors and/or bugs!
    This article was originally published in forum thread: Sorting a Multidimensional Array -- quicksort started by Herb View original post
    Comments 2 Comments
    1. Diptesh's Avatar
      Diptesh -
      I tried tis with other algorithm and it is working for me...

      Following is my script... this script does one more thing..

      This program sorts on multiple columns. U can specify columnindex in sortColArray.

      Currently i hv specified (0,1). This means it will sort on 0th column and if it found similar element in 0th column it will sort based on 1st column index.

      Plz reply me, if this post is useful for u...

      Code:
      
      Array.prototype.swap=function(a, b)
       {
       	var tmp=this[a];
       	this[a]=this[b];
       	this[b]=tmp;
       }
       
       function partition(array, begin, end, pivot)
       {
             var sortColArray= new Array(0,1);
              var ColIndex = 0;
              var secondIndex = sortColArray[ColIndex];
              var piv=array[pivot];
       	array.swap(pivot, end-1);
       	var store=begin;
       	var ix;
              var secondFlag=false;
       	
       	for(ix=begin; ix<end-1; ++ix) {
       		if(array[ix][secondIndex] == piv[secondIndex]) {
      
                              secondIndex = sortColArray[++ColIndex];
                              secondFlag=true;
                      }
      
       		if(array[ix][secondIndex] <= piv[secondIndex]) {
       			array.swap(store, ix);
       			++store;
       		}
                      if(secondFlag == true)
                      {
                         secondIndex = sortColArray[--ColIndex];
                         secondFlag=false;
                      }
       	}
       	array.swap(end-1, store);
       
       	return store;
       }
       
       
       function qsort(array, begin, end)
       {
       	if(end-1>begin) {
       		var pivot=begin+Math.floor(Math.random()*(end-begin));
       
       		pivot=partition(array, begin, end, pivot);
       
       		qsort(array, begin, pivot);
       		qsort(array, pivot+1, end);
       	}
       }
       
       
       function quick_sort(array)
       {
       	qsort(array, 0, array.length);
       }
       
       
       function dosort(array)
       {
      // 	var array=form.unsorted.value.split(/ +/);
       
       	quick_sort(array);
       
       	//form.sorted.value=array.join(' ');
       
       
       }
       
      var array = new Array();
      
      array[0] = new Array ( 21, "Kevin" ,"A");
      array[1] = new Array ( 20, "Alice" ,"B");
      array[2] = new Array ( 23, "Steve" ,"C");
      array[3] = new Array ( 21, "Adam"  ,"D");
      array[4] = new Array ( 26, "Sammy" ,"E");
      array[5] = new Array ( 22, "Adam"  ,"D");
      
      array[6] = new Array ( 23, "Sammy" ,"E");
      array[7] = new Array ( 24, "Sammy" ,"E");
      array[8] = new Array ( 17, "Aammy" ,"H");
      array[9] = new Array ( 18, "Sammy" ,"E");
      array[10] = new Array ( 19, "Sammy" ,"E");
      
      
      array[11] = new Array ( 20, "Sammy" ,"E");
      array[12] = new Array ( 17, "Sammy" ,"E");
      array[13] = new Array ( 18, "Sammy" ,"E");
      array[14] = new Array ( 19, "Sammy" ,"E");
      array[15] = new Array ( 20, "Sammy" ,"E");
      
      array[16] = new Array ( 13, "Sammy" ,"E");
      
      array[17] = new Array ( 14, "Sammy" ,"E");
      array[18] = new Array ( 15, "Sammy" ,"E");
      array[19] = new Array ( 16, "Sammy" ,"E");
      array[20] = new Array ( 13, "Sammy" ,"E");
      array[21] = new Array ( 14, "Sammy" ,"E");
      array[22] = new Array ( 15, "Sammy" ,"E");
      array[23] = new Array ( 16, "Sammy" ,"E");
      array[24] = new Array ( 9, "Sammy" ,"E");
      array[25] = new Array ( 10, "Sammy" ,"E");
      array[26] = new Array ( 11, "Sammy" ,"E");
      array[27] = new Array ( 12, "Sammy" ,"E");
      array[28] = new Array ( 9, "Sammy" ,"E");
      array[29] = new Array ( 10, "Sammy" ,"E");
      array[30] = new Array ( 11, "Sammy" ,"E");
      array[31] = new Array ( 12, "Sammy" ,"E");
      
      dosort(array);
      
      for(var i=0; i<array.length; i++)
      {  document.write(array[i] + "<br />");
      }
    1. c1lonewolf's Avatar
      c1lonewolf -
      ah back online finally...hehehe

      according to your original answer...
      How do I set up a compare function (sorting arrays) for a multi-dimensional array when I want the sort to be based on the first 2 elements of the array.

      If I have the array
      3,Kevin
      3,Alice
      2,Steve
      1,Adam
      2,Sammy

      I want to sort it so I get
      1,Adam
      2,Sammy
      2,Steve
      3,Alice
      3,Kevin
      In this case it's a numeric sorter, looking for array[0][0]
      if sorting alpha style it's array[0][1]. The easiest way is to remove the excess (example:Lady Alena's array) then you reference one element, split it up to search what you need and return in whatever you require. In short, you search & sort only the column needed and return the results.

      I was already working on a sorting project when Lady Alena needed help with hers and came up with a simple alpha / numeric sorying system that works off columns only. Only about 3 function and can sort anything as long as it's setup like hers. I'll see if I can find it!
  • Recent Articles