Quick Sort Custom Tag

Could somebody please tell me where I can get a coldfusion custom tag for quick sort. I went to the Allaire site and downloaded the Merge Sort tag, which works fine, but it takes a very long time. I need a faster solution. Thanks in advance.

Nigel
theoneandonlyAsked:
Who is Participating?
 
CF_SpikeConnect With a Mentor Commented:
ok,

This one works with dates, but you'll have to add the duplicate stuff yourself.

Calling page:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
      <title>Quick Sort</title>
</head>

<body>
<!--- 2 Dimensional array sorting. Second Array dimension represents:
1 - Employee No
2 - Name
3 - Age
4 - Sex
5 - Date of Birth
6 - Department --->

<CFSCRIPT>
  myArray = ArrayNew(2);
  myArray[1][1] = '1';
  myArray[1][2] = 'Spike';
  myArray[1][3] = '28';
  myArray[1][4] = 'Male';
  myArray[1][5] = CreateDate(1972,08,10);
  myArray[1][6] = 'Training';
 
  myArray[2][1] = '2';
  myArray[2][2] = 'Jon';
  myArray[2][3] = '26';
  myArray[2][4] = 'Male';
  myArray[2][5] = CreateDate(1979,10,23);
  myArray[2][6] = 'Consulting';
 
  myArray[3][1] = '3';
  myArray[3][2] = 'Bob';
  myArray[3][3] = '22';
  myArray[3][4] = 'Male';
  myArray[3][5] = CreateDate(1974,03,23);
  myArray[3][6] = 'Sales';
 
  myArray[4][1] = '4';
  myArray[4][2] = 'Jane';
  myArray[4][3] = '20';
  myArray[4][4] = 'Female';
  myArray[4][5] = CreateDate(1980,11,29);
  myArray[4][6] = 'Sales';
 
  myArray[5][1] = '5';
  myArray[5][2] = 'Anne';
  myArray[5][3] = '30';
  myArray[5][4] = 'Female';
  myArray[5][5] = CreateDate(1971,11,29);
  myArray[5][6] = 'Sales';
 
</CFSCRIPT>


<CF_QuickSort  
    Array="#MyArray#"
    r_Array="SortedArray"
    SortType="Date"
    SortItem="5"
    SortOrder="Asc">

</body>
</html>

Custom Tag:

<CFPARAM NAME="Attributes.Array">
<CFPARAM NAME="Attributes.r_Array">

<!--- SortItem is the index in the second dimension
of the array which we want to sort by --->
<CFPARAM NAME="Attributes.SortItem">

<!--- SortType can be Numeric, Text, TextNoCase, date --->
<CFPARAM NAME="Attributes.SortType">

<!--- SortOrder can be Desc, Asc --->
<CFPARAM NAME="Attributes.SortOrder" DEFAULT="Asc">

<!--- Initialize a list to hold the array elements --->
<CFSET NameList = "">

<!--- Loop over the Array creating a list of the
elements by which we want to sort  --->
<CFLOOP From="1" To="#ArrayLen(Attributes.Array)#" index="i">
<CFSET ThisItem = Attributes.Array[i][Attributes.SortItem]>
<CFSET NameList = ListAppend(NameList,ThisItem)>

<!--- Handle the special case where the sort type is date --->
<CFIF NOT CompareNoCase(Attributes.SortType,'Date')>
<!--- Make sure that the sort field is a date field --->
<CFIF NOT IsDate(ThisItem)>
  <CFABORT SHOWERROR="A sort type of date was requested for the custom tag quicksort, but the field to be sorted is not a date field">
</CFIF>
<!--- Initialize the newlist --->
<CFPARAM NAME="NewList" DEFAULT="">
 
  <!--- Only perform the sort once we have an element in the list --->
  <CFIF i GT 1>
    <!--- Loop over the current elements in the sorted list --->
    <CFLOOP FROM="1" TO="#ListLen(NewList)#" INDEX="j">
      <!--- Check if we are doing a descending or ascending sort --->
      <CFIF CompareNoCase(Attributes.SortOrder,'Asc')>
        <!--- Descending sort type --->
     
        <!--- Check if the date is before the the current list element, but after the next --->
        <CFIF DateCompare(ListGetAt(NewList,j),ThisItem) GT 0 AND J LT ListLen(NewList) AND DateCompare(ListGetAt(NewList,J+1),ThisItem) LT 1>
          <CFSET NewList = ListInsertAt(NewList,J+1,ThisItem)>
          <CFBREAK>
        <!--- Check if the date is later than the current element --->
        <CFELSEIF DateCompare(ListGetAt(NewList,j),ThisItem) LT 1>
          <CFSET NewList = ListPrepend(NewList,ThisItem)>
          <CFBREAK>
        <!--- If we got to here the date must go at the end of the list --->
        <CFELSEIF J EQ ListLen(NewList)>
          <CFSET NewList = ListAppend(NewList,ThisItem)>
        </CFIF>
      <CFELSE>
      <!--- Ascending sort type --->
     
        <!--- Check if the date is after the current date, but before the next --->
        <CFIF DateCompare(ListGetAt(NewList,j),ThisItem) LT 1 AND J LT ListLen(NewList) AND DateCompare(ListGetAt(NewList,J+1),ThisItem) GT 0>
          <CFSET NewList = ListInsertAt(NewList,J+1,ThisItem)>
          <CFBREAK>
        <!--- Check if the date is before the current date --->
        <CFELSEIF DateCompare(ListGetAt(NewList,j),ThisItem) GT 0>
          <CFSET NewList = ListPrepend(NewList,ThisItem)>
          <CFBREAK>
        <!--- If we got to here the date must go at the end of the list --->
        <CFELSEIF J EQ ListLen(NewList)>
          <CFSET NewList = ListAppend(NewList,ThisItem)>
        </CFIF>
      </CFIF>
    </CFLOOP>
 
  <!--- First time through the outer loop we put the item in newlist --->
  <CFELSE>
    <CFSET NewList = ListAppend(NewList,ThisItem)>
  </CFIF>
 
</CFIF>

</CFLOOP>

<!--- Create a new sorted list if sort type isn't date. Sorting by the
parameters declared above  --->
<CFIF CompareNoCase(Attributes.SortType,'Date')>
  <CFSET NewList = ListSort(NameList,Attributes.SortType,Attributes.SortOrder)>
</CFIF>
<!--- Create a New array sorted according to our requirements --->
<CFSET NewArray = ArrayNew(2)>
<CFSET Counter = 1>
<CFLOOP LIST="#newList#" INDEX="i">
<CFSET NewArray[counter] = Attributes.Array[ListFind(NameList,i)]>
<CFSET Counter = Counter + 1>
</CFLOOP>

<CFSET "Caller.#Attributes.r_Array#" = NewArray>

Spike
0
 
CF_SpikeCommented:
Exactly what type of quick sort do you want?

Sorting structures, arrays or queries?

Spike
0
 
theoneandonlyAuthor Commented:
0
The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

 
theoneandonlyAuthor Commented:
0
 
theoneandonlyAuthor Commented:
0
 
theoneandonlyAuthor Commented:
0
 
theoneandonlyAuthor Commented:
0
 
theoneandonlyAuthor Commented:
I have written some code, it works but I am not sure how to return the sorted result. It returns only the first pass value.


--------------------------------------------------------

<!---
  Custom Tag:             QuickSort
  Author:                   Nigel Pereira
  Creation_date:      15 June 2001
  Lastmod_date:            15 June 2001
 
  Attributes:            array                        (required) the 2 dimentional array to sort.
                              first                        (required) the first element of the array
                              last                        (required) the last element of the array
                              sortorder                  (optional) order to sort by
                                                            (default = "ASC") (asc,dsc)
                    sorttype                  (required) type of sort order
                                                            (default = "string") (date,string,integer)
                              arraywidth                  (required) the width of the array
                              sortcolumn                  (required) the column to sort by
                              

  Tag Usage:            <CF_QuickSort
                                    array="#arrSortedKey#"
                                    first="1"
                                    last="#ListLen(lStructKeys)#"
                                    sortorder="ASC"
                                    sorttype="date"
                                    arraywidth="#ListLen(lKeys)#"
                                    sortcolumn="#nKeyPos#"
                                    r_sortedArray="arrSorted">
                                    
  Description:            This tag will perform a quick sort on the array passed by the specified column in
                                either ascending or descending order.
--->  
<cfset array = ATTRIBUTES.array>
<cfset First = ATTRIBUTES.first>
<cfset Last = ATTRIBUTES.last>      
<Cfset SortType = "#ATTRIBUTES.SortType#">
<cfset sortcolumn = ATTRIBUTES.sortcolumn>
<cfset ArrayWidth = ATTRIBUTES.ArrayWidth>
<cfset thesortorder = "#ATTRIBUTES.sortorder#">
<cfparam name="Attributes.r_sortedArray" default="">

<!--- Set the structure of the return value --->
<cfif not IsDefined("Caller.#Attributes.r_sortedArray#")>
  <cfset temp= SetVariable("Caller.#Attributes.r_sortedArray#",ArrayNew(2))>
</cfif>

<cfif not IsArray(Evaluate("Caller.#Attributes.r_sortedArray#"))>
  <cfset temp= SetVariable("Caller.#Attributes.r_sortedArray#",ArrayNew(2))>
</cfif>
      
<cfscript>
      lo = first;
      hi = last;
      WriteOutput("Low=#lo# High=#hi#<br>");
</cfscript>
<cfif lo LT hi>
      <cfscript>
            midIndex = Int((lo + hi) / 2);
            mid = array[midIndex][sortcolumn];
            WriteOutput("Mid=#mid#<br>");
            for(k=1;lo LT hi;k=k+1)
            {
                  for(m=1;m LTE ArrayLen(array);m=m+1)
                  {
                        WriteOutput(ArrayToList(array[m]));
                        WriteOutput("      ");
                  }
                  WriteOutput("<br>");
                 for (;lo LT hi AND array[lo][sortcolumn] LT mid;)
                  {
                        lo=lo+1;
                }
                for (;lo LT hi AND array[hi][sortcolumn] GT mid;)
                  {
                        WriteOutput("#array[hi][1]# ");
                        WriteOutput("#array[hi][sortcolumn]#<br>");
                        hi=hi-1;
                }
                if (lo LT hi)
                  {
                        val=ArraySwap(array,lo,hi);
                        //for(i=1;i LTE ArrayWidth;i=i+1)
                        //{
                        //      T = array[lo][i];
                        //      array[lo][i] = array[hi][i];
                        //      array[hi][i] = T;
                        //}
                }
            }
            if (hi LT lo)
            {
                T = hi;
                hi = lo;
                lo = T;
            }
      </cfscript>
      <cf_QuickSort       array="#array#"
                              first="#Attributes.first#"
                              last="#lo#"
                              sortorder="#Attributes.sortorder#"
                              sorttype="#Attributes.sorttype#"
                              arraywidth="#Attributes.arraywidth#"
                              sortcolumn="#Attributes.sortColumn#"
                              r_sortedArray="#Attributes.r_sortedArray#">
      <cfif lo EQ first>
            <cfset lo2=lo+1>
            <cf_QuickSort       array="#array#"
                        first="#lo2#"
                        last="#last#"
                        sortorder="#Attributes.sortorder#"
                        sorttype="#Attributes.sorttype#"
                        arraywidth="#Attributes.arraywidth#"
                        sortcolumn="#Attributes.sortColumn#"
                        r_sortedArray="#Attributes.r_sortedArray#">
      <cfelse>
            <cf_QuickSort       array="#array#"
                        first="#lo#"
                        last="#last#"
                        sortorder="#Attributes.sortorder#"
                        sorttype="#Attributes.sorttype#"
                        arraywidth="#Attributes.arraywidth#"
                        sortcolumn="#Attributes.sortColumn#"
                        r_sortedArray="#Attributes.r_sortedArray#">
      </cfif>
      <cfset temp= SetVariable("Caller.#Attributes.r_sortedArray#",array)>
<cfelse>
      <cfset temp= SetVariable("Caller.#Attributes.r_sortedArray#",array)>
</cfif>
0
 
theoneandonlyAuthor Commented:
Sorry Spike, I wasnt able to respond to your question, The sort I have written is for a 2 dimentional array, containing say employee information:
Employee No, Name, Age, Sex, Date of Birth, Department

Each row in the array contains these fields, I may want to sort based on Employee No, Name, Age, Date of Birth etc.

The code I wrote is correct, in the sense that it sorts the array, but I am not able to return the result, I get the resul from the first pass of the recursion.

Thanks again.

Nigel
0
 
CF_SpikeCommented:
ok,

I'll have a look at it. I've often wanted to write a utility to do something like that.

Spike
0
 
theoneandonlyAuthor Commented:
Cheers Spike.
0
 
CF_SpikeCommented:
Is this what you wanted?

Calling Page:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
     <title>Quick Sort</title>
</head>

<body>
<!--- 2 Dimensional array sorting. Second Array dimension represents:
1 - Employee No
2 - Name
3 - Age
4 - Sex
5 - Date of Birth
6 - Department --->

<CFSCRIPT>
  myArray = ArrayNew(2);
  myArray[1][1] = '1';
  myArray[1][2] = 'Spike';
  myArray[1][3] = '28';
  myArray[1][4] = 'Male';
  myArray[1][5] = 'CreateDate(1972,08,10)';
  myArray[1][6] = 'Training';
 
  myArray[2][1] = '2';
  myArray[2][2] = 'Jon';
  myArray[2][3] = '26';
  myArray[2][4] = 'Male';
  myArray[2][5] = 'CreateDate(1974,10,23)';
  myArray[2][6] = 'Consulting';
 
  myArray[3][1] = '2';
  myArray[3][2] = 'Bob';
  myArray[3][3] = '22';
  myArray[3][4] = 'Male';
  myArray[3][5] = 'CreateDate(1979,03,23)';
  myArray[3][6] = 'Sales';
 
  myArray[4][1] = '2';
  myArray[4][2] = 'Jane';
  myArray[4][3] = '20';
  myArray[4][4] = 'Female';
  myArray[4][5] = 'CreateDate(1980,11,29)';
  myArray[4][6] = 'Sales';
 
</CFSCRIPT>

<CF_QuickSort  
    Array="#MyArray#"
    r_Array="SortedArray"
    SortType="Numeric"
    SortItem="1">


</body>
</html>


custom Tag:

<CFPARAM NAME="Attributes.Array">
<CFPARAM NAME="Attributes.r_Array">

<!--- SortItem is the index in the second dimension
of the array which we want to sort by --->
<CFPARAM NAME="Attributes.SortItem">

<!--- SortType can be Numeric, Text, TextNoCase --->
<CFPARAM NAME="Attributes.SortType">

<!--- SortOrder can be Desc, Asc --->
<CFPARAM NAME="Attributes.SortOrder" DEFAULT="Asc">

<!--- Initialize a list to hold the array elements --->
<CFSET NameList = "">

<!--- Loop over the Array creating a list of the
elements by which we want to sort  --->
<CFLOOP From="1" To="#ArrayLen(Attributes.Array)#" index="i">

  <CFSET NameList = ListAppend(NameList,Attributes.Array[i][Attributes.SortItem])>

</CFLOOP>

<!--- Create a new sorted list. Sorting by the
parameters delcared above --->
<CFSET NewList = ListSort(NameList,Attributes.SortType,Attributes.SortOrder)>

<!--- Create a New array sorted according to our requirements --->
<CFSET NewArray = ArrayNew(2)>
<CFSET Counter = 1>
<CFLOOP LIST="#newList#" INDEX="i">
<CFSET NewArray[counter] = Attributes.Array[ListFind(NameList,i)]>
<CFSET Counter = Counter + 1>
</CFLOOP>

<CFSET "Caller.#Attributes.r_Array#" = NewArray>

Spike
0
 
theoneandonlyAuthor Commented:
Give me a couple of minutes Spike, I'll just check it.
0
 
theoneandonlyAuthor Commented:
Thats great thanks, I think I have to modify it for date sort and also it does not work for duplicate values on the sort index.

Nigel
0
 
CF_SpikeCommented:
That shouldn't be too hard.

Let me know if you have any problems.

Spike
0
 
theoneandonlyAuthor Commented:
Thats great thanks, I think I have to modify it for date sort and also it does not work for duplicate values on the sort index.

Nigel
0
 
theoneandonlyAuthor Commented:
Spike,

Sorry to bother you again, I cant seem to figure out how to do it, could you help me. I tried to remove the array element from the original array after setting it to the new array. But, I am getting an error.

Error Occurred While Processing Request
Error Diagnostic Information

An error occurred while evaluating the expression:


 NewArray[counter] = Attributes.Array[ListFind(NameList,i)]



Error near line 33, column 15.
--------------------------------------------------------------------------------

The [] operator can only be applied to an indexed object. The provided object "Attributes.Array" is not indexed in dimension 1. In ColdFusion indexed objects can be query columns, arrays and structs.


The error occurred while processing an element with a general identifier of (CFSET), occupying document position (33:1) to (33:66).


Date/Time: 06/26/01 17:19:00
Browser: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0)
Remote Address: 127.0.0.1

Thanks.

Nigel
0
 
CF_SpikeCommented:
Erm...

ok, but what were you trying to achieve when this happened?

Spike
0
 
theoneandonlyAuthor Commented:
I sorted out the duplicate things, all I have to do is the date sort. Thanks
0
 
theoneandonlyAuthor Commented:
Thanks a lot Spike I sussed it out myself yesterday.

Nigel
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.