Search code examples
coldfusion

Sorting an array of structs by 2 keys


I have the following data :

arTicker = [];
arTicker[1] = { "vid" : 100,
                "symbol" : "apple" };
arTicker[2] = { "vid" : 101,
                "symbol" : "dell" };
arTicker[3] = { "vid" : 102,
                "symbol" : "ibm" };                    
arTicker[4] = { "vid" : 110,
                "symbol" : "apple" };                        
arTicker[5] = { "vid" : 95,
                "symbol" : "apple" };                        
arTicker[6] = { "vid" : 115,
                "symbol" : "samsung" };    
arTicker[7] = { "vid" : 121,
                "symbol" : "dell" };      
arTicker[8] = { "vid" : 97,
                "symbol" : "apple" };    
arTicker[9] = { "vid" : 107,
                "symbol" : "ibm" };     

I am trying to sort this array by symbol name and including the max vid for that symbol. In doing so, this is my desired output :

apple    | 110
dell     | 121
ibm      | 107
samsung  | 115  

This is what I tried

arraySort(
    arTicker,
    function (e1, e2){
        return compare(e1.symbol, e2.symbol) // && e1.vid < e2.vid;
    }
);
writeDump(arTicker); 

Any suggestions?


Solution

  • This may be a bit too much.

    <cfscript>
        arTicker = [];
        arTicker[1] = { "vid" : 100, "symbol" : "apple" };
        arTicker[2] = { "vid" : 101, "symbol" : "dell" };
        arTicker[3] = { "vid" : 102, "symbol" : "ibm" };                    
        arTicker[4] = { "vid" : 110, "symbol" : "apple" };                        
        arTicker[5] = { "vid" : 95, "symbol" : "apple" };                        
        arTicker[6] = { "vid" : 115, "symbol" : "samsung" };    
        arTicker[7] = { "vid" : 121, "symbol" : "dell" };      
        arTicker[8] = { "vid" : 97, "symbol" : "apple" };    
        arTicker[9] = { "vid" : 107, "symbol" : "ibm" };     
        tracker = [];
        zeroPadding = '0000';
        finalArray = arTicker
            .sort(
                function (e1, e2){
                    return compare(
                        e1.symbol & '-' & numberFormat(e1.vid,zeroPadding),
                        e2.symbol & '-' & numberFormat(e2.vid,zeroPadding)
                    );
                }
            )
            .reduce(
                function (shell, element){
                    shell[element.symbol] = element;
                    return shell;
                },
                structNew( "ordered" )
            ).reduce(
                function (shell, key, element){
                    shell.append(element);
                    return shell;
                },
                []
            );
        writeDump(finalArray); 
    </cfscript>
    

    I am combining symbol and vid and comparing the combination as string. Since the vid is a number I am padding them with 0 to make it as the same length so that the sort of number as string does not cause issues.

    Then from the sorted array create an ordered struct using reduce(struct will have the last item in the group of symbols which is the max(). Then use reduce on the structure again to get the array back.

    DEMO

    For Coldfusion 11, there are similar solutions.

    //ArraySort mutates the array return true or false
    ArraySort(
        arTicker,
        function (e1, e2){
            return compare(
                e1.symbol & '-' & numberFormat(e1.vid,zeroPadding),
                e2.symbol & '-' & numberFormat(e2.vid,zeroPadding)
            );
        }
    );
    
    finalArray = StructReduce(
        ArrayReduce(
            arTicker,
            function (shell, element){
                shell[element.symbol] = element;
                return shell;
            },
            {}
        ),
        function (shell, key, element){
            shell.append(element);
            return shell;
        },
        []
    );